1
ļ»æ// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
3
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
4
// software and associated documentation files (the "Software"), to deal in the Software
5
// without restriction, including without limitation the rights to use, copy, modify, merge,
6
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
7
// to whom the Software is furnished to do so, subject to the following conditions:
9
// The above copyright notice and this permission notice shall be included in all copies or
10
// substantial portions of the Software.
12
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
15
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
17
// DEALINGS IN THE SOFTWARE.
20
using System.Collections.Generic;
21
using System.Diagnostics;
24
using System.Threading;
25
using ICSharpCode.NRefactory.CSharp.Analysis;
26
using ICSharpCode.NRefactory.CSharp.TypeSystem;
27
using ICSharpCode.NRefactory.Semantics;
28
using ICSharpCode.NRefactory.TypeSystem;
29
using ICSharpCode.NRefactory.TypeSystem.Implementation;
31
namespace ICSharpCode.NRefactory.CSharp.Resolver
34
/// Traverses the DOM and resolves expressions.
37
/// The ResolveVisitor does two jobs at the same time: it tracks the resolve context (properties on CSharpResolver)
38
/// and it resolves the expressions visited.
39
/// To allow using the context tracking without having to resolve every expression in the file (e.g. when you want to resolve
40
/// only a single node deep within the DOM), you can use the <see cref="IResolveVisitorNavigator"/> interface.
41
/// The navigator allows you to switch the between scanning mode and resolving mode.
42
/// In scanning mode, the context is tracked (local variables registered etc.), but nodes are not resolved.
43
/// While scanning, the navigator will get asked about every node that the resolve visitor is about to enter.
44
/// This allows the navigator whether to keep scanning, whether switch to resolving mode, or whether to completely skip the
45
/// subtree rooted at that node.
47
/// In resolving mode, the context is tracked and nodes will be resolved.
48
/// The resolve visitor may decide that it needs to resolve other nodes as well in order to resolve the current node.
49
/// In this case, those nodes will be resolved automatically, without asking the navigator interface.
50
/// For child nodes that are not essential to resolving, the resolve visitor will switch back to scanning mode (and thus will
51
/// ask the navigator for further instructions).
53
/// Moreover, there is the <c>ResolveAll</c> mode - it works similar to resolving mode, but will not switch back to scanning mode.
54
/// The whole subtree will be resolved without notifying the navigator.
56
sealed class ResolveVisitor : IAstVisitor<ResolveResult>
58
// The ResolveVisitor is also responsible for handling lambda expressions.
60
static readonly ResolveResult errorResult = ErrorResolveResult.UnknownError;
62
CSharpResolver resolver;
63
/// <summary>Resolve result of the current LINQ query.</summary>
64
/// <remarks>We do not have to put this into the stored state (resolver) because
65
/// query expressions are always resolved in a single operation.</remarks>
66
ResolveResult currentQueryResult;
67
readonly CSharpUnresolvedFile unresolvedFile;
68
readonly Dictionary<AstNode, ResolveResult> resolveResultCache = new Dictionary<AstNode, ResolveResult>();
69
readonly Dictionary<AstNode, CSharpResolver> resolverBeforeDict = new Dictionary<AstNode, CSharpResolver>();
70
readonly Dictionary<AstNode, CSharpResolver> resolverAfterDict = new Dictionary<AstNode, CSharpResolver>();
71
readonly Dictionary<Expression, ConversionWithTargetType> conversionDict = new Dictionary<Expression, ConversionWithTargetType>();
73
internal struct ConversionWithTargetType
75
public readonly Conversion Conversion;
76
public readonly IType TargetType;
78
public ConversionWithTargetType(Conversion conversion, IType targetType)
80
this.Conversion = conversion;
81
this.TargetType = targetType;
85
IResolveVisitorNavigator navigator;
87
List<LambdaBase> undecidedLambdas;
88
internal CancellationToken cancellationToken;
91
static readonly IResolveVisitorNavigator skipAllNavigator = new ConstantModeResolveVisitorNavigator(ResolveVisitorNavigationMode.Skip, null);
94
/// Creates a new ResolveVisitor instance.
96
public ResolveVisitor(CSharpResolver resolver, CSharpUnresolvedFile unresolvedFile)
99
throw new ArgumentNullException("resolver");
100
this.resolver = resolver;
101
this.unresolvedFile = unresolvedFile;
102
this.navigator = skipAllNavigator;
105
internal void SetNavigator(IResolveVisitorNavigator navigator)
107
this.navigator = navigator ?? skipAllNavigator;
110
ResolveResult voidResult {
112
return new ResolveResult(resolver.Compilation.FindType(KnownTypeCode.Void));
119
/// Resets the visitor to the stored position, runs the action, and then reverts the visitor to the previous position.
121
void ResetContext(CSharpResolver storedContext, Action action)
123
var oldResolverEnabled = this.resolverEnabled;
124
var oldResolver = this.resolver;
125
var oldQueryResult = this.currentQueryResult;
127
this.resolverEnabled = false;
128
this.resolver = storedContext;
129
this.currentQueryResult = null;
133
this.resolverEnabled = oldResolverEnabled;
134
this.resolver = oldResolver;
135
this.currentQueryResult = oldQueryResult;
140
#region Scan / Resolve
142
/// Scans the AST rooted at the given node.
144
public void Scan(AstNode node)
146
if (node == null || node.IsNull)
148
switch (node.NodeType) {
150
case NodeType.Whitespace:
151
return; // skip tokens, identifiers, comments, etc.
153
// don't Scan again if the node was already resolved
154
if (resolveResultCache.ContainsKey(node)) {
155
// Restore state change caused by this node:
156
CSharpResolver newResolver;
157
if (resolverAfterDict.TryGetValue(node, out newResolver))
158
resolver = newResolver;
162
var mode = navigator.Scan(node);
164
case ResolveVisitorNavigationMode.Skip:
165
if (node is VariableDeclarationStatement || node is SwitchSection) {
166
// Enforce scanning of variable declarations.
167
goto case ResolveVisitorNavigationMode.Scan;
169
StoreCurrentState(node);
171
case ResolveVisitorNavigationMode.Scan:
172
bool oldResolverEnabled = resolverEnabled;
173
var oldResolver = resolver;
174
resolverEnabled = false;
175
StoreCurrentState(node);
176
ResolveResult result = node.AcceptVisitor(this);
177
if (result != null) {
178
// If the node was resolved, store the result even though it wasn't requested.
179
// This is necessary so that Visit-methods that decide to always resolve are
180
// guaranteed to get called only once.
181
// This is used for lambda registration.
182
StoreResult(node, result);
183
if (resolver != oldResolver) {
184
// The node changed the resolver state:
185
resolverAfterDict.Add(node, resolver);
187
cancellationToken.ThrowIfCancellationRequested();
189
resolverEnabled = oldResolverEnabled;
191
case ResolveVisitorNavigationMode.Resolve:
195
throw new InvalidOperationException("Invalid value for ResolveVisitorNavigationMode");
200
/// Equivalent to 'Scan', but also resolves the node at the same time.
201
/// This method should be only used if the CSharpResolver passed to the ResolveVisitor was manually set
202
/// to the correct state.
203
/// Otherwise, use <c>resolver.Scan(syntaxTree); var result = resolver.GetResolveResult(node);</c>
206
/// This method now is internal, because it is difficult to use correctly.
207
/// Users of the public API should use Scan()+GetResolveResult() instead.
209
internal ResolveResult Resolve(AstNode node)
211
if (node == null || node.IsNull)
213
bool oldResolverEnabled = resolverEnabled;
214
resolverEnabled = true;
215
ResolveResult result;
216
if (!resolveResultCache.TryGetValue(node, out result)) {
217
cancellationToken.ThrowIfCancellationRequested();
218
StoreCurrentState(node);
219
var oldResolver = resolver;
220
result = node.AcceptVisitor(this) ?? errorResult;
221
StoreResult(node, result);
222
if (resolver != oldResolver) {
223
// The node changed the resolver state:
224
resolverAfterDict.Add(node, resolver);
227
resolverEnabled = oldResolverEnabled;
231
IType ResolveType(AstType type)
233
return Resolve(type).Type;
236
void StoreCurrentState(AstNode node)
238
// It's possible that we re-visit an expression that we scanned over earlier,
239
// so we might have to overwrite an existing state.
242
CSharpResolver oldResolver;
243
if (resolverBeforeDict.TryGetValue(node, out oldResolver)) {
244
Debug.Assert(oldResolver.LocalVariables.SequenceEqual(resolver.LocalVariables));
248
resolverBeforeDict[node] = resolver;
251
void StoreResult(AstNode node, ResolveResult result)
253
Debug.Assert(result != null);
256
Log.WriteLine("Resolved '{0}' to {1}", node, result);
257
Debug.Assert(!CSharpAstResolver.IsUnresolvableNode(node));
258
// The state should be stored before the result is.
259
Debug.Assert(resolverBeforeDict.ContainsKey(node));
260
// Don't store results twice.
261
Debug.Assert(!resolveResultCache.ContainsKey(node));
262
resolveResultCache[node] = result;
263
if (navigator != null)
264
navigator.Resolved(node, result);
267
void ScanChildren(AstNode node)
269
for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) {
275
#region Process Conversions
276
sealed class AnonymousFunctionConversion : Conversion
278
public readonly IType ReturnType;
279
public readonly ExplicitlyTypedLambda ExplicitlyTypedLambda;
280
public readonly LambdaTypeHypothesis Hypothesis;
281
readonly bool isValid;
283
public AnonymousFunctionConversion(IType returnType, LambdaTypeHypothesis hypothesis, bool isValid)
285
if (returnType == null)
286
throw new ArgumentNullException("returnType");
287
this.ReturnType = returnType;
288
this.Hypothesis = hypothesis;
289
this.isValid = isValid;
292
public AnonymousFunctionConversion(IType returnType, ExplicitlyTypedLambda explicitlyTypedLambda, bool isValid)
294
if (returnType == null)
295
throw new ArgumentNullException("returnType");
296
this.ReturnType = returnType;
297
this.ExplicitlyTypedLambda = explicitlyTypedLambda;
298
this.isValid = isValid;
301
public override bool IsValid {
302
get { return isValid; }
305
public override bool IsImplicit {
309
public override bool IsAnonymousFunctionConversion {
315
/// Convert 'rr' to the target type using the specified conversion.
317
void ProcessConversion(Expression expr, ResolveResult rr, Conversion conversion, IType targetType)
319
AnonymousFunctionConversion afc = conversion as AnonymousFunctionConversion;
321
Log.WriteLine("Processing conversion of anonymous function to " + targetType + "...");
324
if (afc.Hypothesis != null)
325
afc.Hypothesis.MergeInto(this, afc.ReturnType);
326
if (afc.ExplicitlyTypedLambda != null)
327
afc.ExplicitlyTypedLambda.ApplyReturnType(this, afc.ReturnType);
330
if (expr != null && !expr.IsNull && conversion != Conversion.IdentityConversion) {
331
navigator.ProcessConversion(expr, rr, conversion, targetType);
332
conversionDict[expr] = new ConversionWithTargetType(conversion, targetType);
336
void ImportConversions(ResolveVisitor childVisitor)
338
foreach (var pair in childVisitor.conversionDict) {
339
conversionDict.Add(pair.Key, pair.Value);
340
navigator.ProcessConversion(pair.Key, resolveResultCache[pair.Key], pair.Value.Conversion, pair.Value.TargetType);
345
/// Convert 'rr' to the target type.
347
void ProcessConversion(Expression expr, ResolveResult rr, IType targetType)
349
if (expr == null || expr.IsNull)
351
ProcessConversion(expr, rr, resolver.conversions.ImplicitConversion(rr, targetType), targetType);
355
/// Resolves the specified expression and processes the conversion to targetType.
357
void ResolveAndProcessConversion(Expression expr, IType targetType)
359
if (targetType.Kind == TypeKind.Unknown || targetType.Kind == TypeKind.Void) {
360
// no need to resolve the expression right now
363
ProcessConversion(expr, Resolve(expr), targetType);
367
void ProcessConversionResult(Expression expr, ConversionResolveResult rr)
370
ProcessConversion(expr, rr.Input, rr.Conversion, rr.Type);
373
void ProcessConversionResults(IEnumerable<Expression> expr, IEnumerable<ResolveResult> conversionResolveResults)
375
Debug.Assert(expr.Count() == conversionResolveResults.Count());
376
using (var e1 = expr.GetEnumerator()) {
377
using (var e2 = conversionResolveResults.GetEnumerator()) {
378
while (e1.MoveNext() && e2.MoveNext()) {
379
ProcessConversionResult(e1.Current, e2.Current as ConversionResolveResult);
385
void MarkUnknownNamedArguments(IEnumerable<Expression> arguments)
387
foreach (var nae in arguments.OfType<NamedArgumentExpression>()) {
388
StoreCurrentState(nae);
389
StoreResult(nae, new NamedArgumentResolveResult(nae.Name, resolveResultCache[nae.Expression]));
393
void ProcessInvocationResult(Expression target, IEnumerable<Expression> arguments, ResolveResult invocation)
395
if (invocation is CSharpInvocationResolveResult || invocation is DynamicInvocationResolveResult) {
397
IList<ResolveResult> argumentsRR;
398
if (invocation is CSharpInvocationResolveResult) {
399
var csi = (CSharpInvocationResolveResult)invocation;
400
if (csi.IsExtensionMethodInvocation) {
401
Debug.Assert(arguments.Count() + 1 == csi.Arguments.Count);
402
ProcessConversionResult(target, csi.Arguments[0] as ConversionResolveResult);
405
Debug.Assert(arguments.Count() == csi.Arguments.Count);
407
argumentsRR = csi.Arguments;
410
argumentsRR = ((DynamicInvocationResolveResult)invocation).Arguments;
413
foreach (Expression arg in arguments) {
414
ResolveResult argRR = argumentsRR[i++];
415
NamedArgumentExpression nae = arg as NamedArgumentExpression;
416
NamedArgumentResolveResult nrr = argRR as NamedArgumentResolveResult;
417
Debug.Assert((nae == null) == (nrr == null));
418
if (nae != null && nrr != null) {
419
StoreCurrentState(nae);
420
StoreResult(nae, nrr);
421
ProcessConversionResult(nae.Expression, nrr.Argument as ConversionResolveResult);
423
ProcessConversionResult(arg, argRR as ConversionResolveResult);
428
MarkUnknownNamedArguments(arguments);
433
#region GetResolveResult
435
/// Gets the resolve result for the specified node.
436
/// If the node was not resolved by the navigator, this method will resolve it.
438
public ResolveResult GetResolveResult(AstNode node)
440
Debug.Assert(!CSharpAstResolver.IsUnresolvableNode(node));
442
MergeUndecidedLambdas();
443
ResolveResult result;
444
if (resolveResultCache.TryGetValue(node, out result))
448
CSharpResolver storedResolver = GetPreviouslyScannedContext(node, out parent);
452
navigator = new NodeListResolveVisitorNavigator(node);
453
Debug.Assert(!resolverEnabled);
455
navigator = skipAllNavigator;
458
MergeUndecidedLambdas();
459
return resolveResultCache[node];
462
CSharpResolver GetPreviouslyScannedContext(AstNode node, out AstNode parent)
465
CSharpResolver storedResolver;
466
while (!resolverBeforeDict.TryGetValue(parent, out storedResolver)) {
467
parent = parent.Parent;
469
throw new InvalidOperationException("Could not find a resolver state for any parent of the specified node. Are you trying to resolve a node that is not a descendant of the CSharpAstResolver's root node?");
471
return storedResolver;
475
/// Gets the resolver state in front of the specified node.
476
/// If the node was not visited by a previous scanning process, the
477
/// AST will be scanned again to determine the state.
479
public CSharpResolver GetResolverStateBefore(AstNode node)
481
MergeUndecidedLambdas();
483
if (resolverBeforeDict.TryGetValue(node, out r))
487
CSharpResolver storedResolver = GetPreviouslyScannedContext(node, out parent);
491
navigator = new NodeListResolveVisitorNavigator(new[] { node }, scanOnly: true);
492
Debug.Assert(!resolverEnabled);
493
// parent might already be resolved if 'node' is an unresolvable node
495
navigator = skipAllNavigator;
498
MergeUndecidedLambdas();
499
while (node != null) {
500
if (resolverBeforeDict.TryGetValue(node, out r))
507
public CSharpResolver GetResolverStateAfter(AstNode node)
509
// Resolve the node to fill the resolverAfterDict
510
GetResolveResult(node);
511
CSharpResolver result;
512
if (resolverAfterDict.TryGetValue(node, out result))
515
return GetResolverStateBefore(node);
518
public ConversionWithTargetType GetConversionWithTargetType(Expression expr)
520
GetResolverStateBefore(expr);
521
ResolveParentForConversion(expr);
522
ConversionWithTargetType result;
523
if (conversionDict.TryGetValue(expr, out result)) {
526
ResolveResult rr = GetResolveResult(expr);
527
return new ConversionWithTargetType(Conversion.IdentityConversion, rr.Type);
532
#region Track UsingScope
533
ResolveResult IAstVisitor<ResolveResult>.VisitSyntaxTree(SyntaxTree unit)
535
CSharpResolver previousResolver = resolver;
537
if (unresolvedFile != null) {
538
resolver = resolver.WithCurrentUsingScope(unresolvedFile.RootUsingScope.Resolve(resolver.Compilation));
540
var cv = new TypeSystemConvertVisitor(unit.FileName ?? string.Empty);
541
ApplyVisitorToUsings(cv, unit.Children);
542
PushUsingScope(cv.UnresolvedFile.RootUsingScope);
547
resolver = previousResolver;
551
void ApplyVisitorToUsings(TypeSystemConvertVisitor visitor, IEnumerable<AstNode> children)
553
foreach (var child in children) {
554
if (child is ExternAliasDeclaration || child is UsingDeclaration || child is UsingAliasDeclaration) {
555
child.AcceptVisitor(visitor);
560
void PushUsingScope(UsingScope usingScope)
563
resolver = resolver.WithCurrentUsingScope(new ResolvedUsingScope(resolver.CurrentTypeResolveContext, usingScope));
566
ResolveResult IAstVisitor<ResolveResult>.VisitNamespaceDeclaration(NamespaceDeclaration namespaceDeclaration)
568
CSharpResolver previousResolver = resolver;
570
if (unresolvedFile != null) {
571
resolver = resolver.WithCurrentUsingScope(unresolvedFile.GetUsingScope(namespaceDeclaration.StartLocation).Resolve(resolver.Compilation));
573
// string fileName = namespaceDeclaration.GetRegion().FileName ?? string.Empty;
574
// Fetch parent using scope
575
// Create root using scope if necessary
576
if (resolver.CurrentUsingScope == null)
577
PushUsingScope(new UsingScope());
579
// Create child using scope
580
DomRegion region = namespaceDeclaration.GetRegion();
581
var identifiers = namespaceDeclaration.Identifiers.ToList();
582
// For all but the last identifier:
583
UsingScope usingScope;
584
for (int i = 0; i < identifiers.Count - 1; i++) {
585
usingScope = new UsingScope(resolver.CurrentUsingScope.UnresolvedUsingScope, identifiers[i].Name);
586
usingScope.Region = region;
587
PushUsingScope(usingScope);
590
usingScope = new UsingScope(resolver.CurrentUsingScope.UnresolvedUsingScope, identifiers.Last().Name);
591
usingScope.Region = region;
592
var cv = new TypeSystemConvertVisitor(new CSharpUnresolvedFile(region.FileName ?? string.Empty), usingScope);
593
ApplyVisitorToUsings(cv, namespaceDeclaration.Children);
594
PushUsingScope(usingScope);
596
ScanChildren(namespaceDeclaration);
597
// merge undecided lambdas before leaving the using scope so that
598
// the resolver can make better use of its cache
599
MergeUndecidedLambdas();
600
if (resolver.CurrentUsingScope != null && resolver.CurrentUsingScope.Namespace != null)
601
return new NamespaceResolveResult(resolver.CurrentUsingScope.Namespace);
605
resolver = previousResolver;
610
#region Track CurrentTypeDefinition
611
ResolveResult VisitTypeOrDelegate(AstNode typeDeclaration, string name, int typeParameterCount)
613
CSharpResolver previousResolver = resolver;
615
ITypeDefinition newTypeDefinition = null;
616
if (resolver.CurrentTypeDefinition != null) {
617
int totalTypeParameterCount = resolver.CurrentTypeDefinition.TypeParameterCount + typeParameterCount;
618
foreach (ITypeDefinition nestedType in resolver.CurrentTypeDefinition.NestedTypes) {
619
if (nestedType.Name == name && nestedType.TypeParameterCount == totalTypeParameterCount) {
620
newTypeDefinition = nestedType;
624
} else if (resolver.CurrentUsingScope != null) {
625
newTypeDefinition = resolver.CurrentUsingScope.Namespace.GetTypeDefinition(name, typeParameterCount);
627
if (newTypeDefinition != null)
628
resolver = resolver.WithCurrentTypeDefinition(newTypeDefinition);
630
ScanChildren(typeDeclaration);
632
// merge undecided lambdas before leaving the type definition so that
633
// the resolver can make better use of its cache
634
MergeUndecidedLambdas();
636
return newTypeDefinition != null ? new TypeResolveResult(newTypeDefinition) : errorResult;
638
resolver = previousResolver;
642
ResolveResult IAstVisitor<ResolveResult>.VisitTypeDeclaration(TypeDeclaration typeDeclaration)
644
return VisitTypeOrDelegate(typeDeclaration, typeDeclaration.Name, typeDeclaration.TypeParameters.Count);
647
ResolveResult IAstVisitor<ResolveResult>.VisitDelegateDeclaration(DelegateDeclaration delegateDeclaration)
649
return VisitTypeOrDelegate(delegateDeclaration, delegateDeclaration.Name, delegateDeclaration.TypeParameters.Count);
653
#region Track CurrentMember
654
ResolveResult IAstVisitor<ResolveResult>.VisitFieldDeclaration(FieldDeclaration fieldDeclaration)
656
return VisitFieldOrEventDeclaration(fieldDeclaration, EntityType.Field);
659
ResolveResult IAstVisitor<ResolveResult>.VisitFixedFieldDeclaration(FixedFieldDeclaration fixedFieldDeclaration)
661
return VisitFieldOrEventDeclaration(fixedFieldDeclaration, EntityType.Field);
664
ResolveResult IAstVisitor<ResolveResult>.VisitEventDeclaration(EventDeclaration eventDeclaration)
666
return VisitFieldOrEventDeclaration(eventDeclaration, EntityType.Event);
669
ResolveResult VisitFieldOrEventDeclaration(EntityDeclaration fieldOrEventDeclaration, EntityType entityType)
671
//int initializerCount = fieldOrEventDeclaration.GetChildrenByRole(Roles.Variable).Count;
672
CSharpResolver oldResolver = resolver;
673
for (AstNode node = fieldOrEventDeclaration.FirstChild; node != null; node = node.NextSibling) {
674
if (node.Role == Roles.Variable) {
676
if (unresolvedFile != null) {
677
member = GetMemberFromLocation(node);
679
string name = ((VariableInitializer)node).Name;
680
member = AbstractUnresolvedMember.Resolve(resolver.CurrentTypeResolveContext, entityType, name);
682
resolver = resolver.WithCurrentMember(member);
686
resolver = oldResolver;
694
IMember GetMemberFromLocation(AstNode node)
696
ITypeDefinition typeDef = resolver.CurrentTypeDefinition;
699
TextLocation location = TypeSystemConvertVisitor.GetStartLocationAfterAttributes(node);
700
return typeDef.GetMembers(
701
delegate (IUnresolvedMember m) {
702
if (m.UnresolvedFile != unresolvedFile)
704
DomRegion region = m.Region;
705
return !region.IsEmpty && region.Begin <= location && region.End > location;
707
GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions
711
ResolveResult IAstVisitor<ResolveResult>.VisitVariableInitializer(VariableInitializer variableInitializer)
713
// Within the variable initializer, the newly declared variable is not yet available:
714
var resolverWithVariable = resolver;
715
if (variableInitializer.Parent is VariableDeclarationStatement)
716
resolver = resolver.PopLastVariable();
718
ArrayInitializerExpression aie = variableInitializer.Initializer as ArrayInitializerExpression;
719
if (resolverEnabled || aie != null) {
720
ResolveResult result = errorResult;
721
if (variableInitializer.Parent is FieldDeclaration || variableInitializer.Parent is EventDeclaration) {
722
if (resolver.CurrentMember != null) {
723
result = new MemberResolveResult(null, resolver.CurrentMember, false);
726
string identifier = variableInitializer.Name;
727
foreach (IVariable v in resolverWithVariable.LocalVariables) {
728
if (v.Name == identifier) {
729
result = new LocalResolveResult(v);
734
ArrayType arrayType = result.Type as ArrayType;
735
if (aie != null && arrayType != null) {
736
StoreCurrentState(aie);
737
List<Expression> initializerElements = new List<Expression>();
738
int[] sizes = new int[arrayType.Dimensions];
739
UnpackArrayInitializer(initializerElements, sizes, aie, 0, true);
740
ResolveResult[] initializerElementResults = new ResolveResult[initializerElements.Count];
741
for (int i = 0; i < initializerElementResults.Length; i++) {
742
initializerElementResults[i] = Resolve(initializerElements[i]);
744
var arrayCreation = resolver.ResolveArrayCreation(arrayType.ElementType, sizes, initializerElementResults);
745
StoreResult(aie, arrayCreation);
746
ProcessConversionResults(initializerElements, arrayCreation.InitializerElements);
747
} else if (variableInitializer.Parent is FixedStatement) {
748
var initRR = Resolve(variableInitializer.Initializer);
749
PointerType pointerType;
750
if (initRR.Type.Kind == TypeKind.Array) {
751
pointerType = new PointerType(((ArrayType)initRR.Type).ElementType);
752
} else if (ReflectionHelper.GetTypeCode(initRR.Type) == TypeCode.String) {
753
pointerType = new PointerType(resolver.Compilation.FindType(KnownTypeCode.Char));
756
ProcessConversion(variableInitializer.Initializer, initRR, result.Type);
758
if (pointerType != null) {
759
var conversion = resolver.conversions.ImplicitConversion(pointerType, result.Type);
760
if (conversion.IsIdentityConversion)
761
conversion = Conversion.ImplicitPointerConversion;
762
ProcessConversion(variableInitializer.Initializer, initRR, conversion, result.Type);
765
ResolveAndProcessConversion(variableInitializer.Initializer, result.Type);
767
resolver = resolverWithVariable;
770
Scan(variableInitializer.Initializer);
771
resolver = resolverWithVariable;
776
ResolveResult IAstVisitor<ResolveResult>.VisitFixedVariableInitializer(FixedVariableInitializer fixedVariableInitializer)
778
if (resolverEnabled) {
779
ResolveResult result = errorResult;
780
if (resolver.CurrentMember != null) {
781
result = new MemberResolveResult(null, resolver.CurrentMember, false);
783
ResolveAndProcessConversion(fixedVariableInitializer.CountExpression, resolver.Compilation.FindType(KnownTypeCode.Int32));
786
ScanChildren(fixedVariableInitializer);
791
ResolveResult VisitMethodMember(EntityDeclaration memberDeclaration)
793
CSharpResolver oldResolver = resolver;
796
if (unresolvedFile != null) {
797
member = GetMemberFromLocation(memberDeclaration);
799
// Re-discover the method:
800
EntityType entityType = memberDeclaration.EntityType;
801
var parameterTypes = TypeSystemConvertVisitor.GetParameterTypes(memberDeclaration.GetChildrenByRole(Roles.Parameter), InterningProvider.Dummy);
802
if (entityType == EntityType.Constructor) {
803
string name = memberDeclaration.HasModifier(Modifiers.Static) ? ".cctor" : ".ctor";
804
member = AbstractUnresolvedMember.Resolve(
805
resolver.CurrentTypeResolveContext, entityType, name,
806
parameterTypeReferences: parameterTypes);
807
} else if (entityType == EntityType.Destructor) {
808
member = AbstractUnresolvedMember.Resolve(resolver.CurrentTypeResolveContext, entityType, "Finalize");
810
string[] typeParameterNames = memberDeclaration.GetChildrenByRole(Roles.TypeParameter).Select(tp => tp.Name).ToArray();
811
AstType explicitInterfaceAstType = memberDeclaration.GetChildByRole(EntityDeclaration.PrivateImplementationTypeRole);
812
ITypeReference explicitInterfaceType = null;
813
if (!explicitInterfaceAstType.IsNull) {
814
explicitInterfaceType = explicitInterfaceAstType.ToTypeReference();
816
member = AbstractUnresolvedMember.Resolve(
817
resolver.CurrentTypeResolveContext, entityType, memberDeclaration.Name,
818
explicitInterfaceType, typeParameterNames, parameterTypes);
821
resolver = resolver.WithCurrentMember(member);
822
ScanChildren(memberDeclaration);
825
return new MemberResolveResult(null, member, false);
829
resolver = oldResolver;
833
ResolveResult IAstVisitor<ResolveResult>.VisitMethodDeclaration(MethodDeclaration methodDeclaration)
835
return VisitMethodMember(methodDeclaration);
838
ResolveResult IAstVisitor<ResolveResult>.VisitOperatorDeclaration(OperatorDeclaration operatorDeclaration)
840
return VisitMethodMember(operatorDeclaration);
843
ResolveResult IAstVisitor<ResolveResult>.VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration)
845
return VisitMethodMember(constructorDeclaration);
848
ResolveResult IAstVisitor<ResolveResult>.VisitDestructorDeclaration(DestructorDeclaration destructorDeclaration)
850
return VisitMethodMember(destructorDeclaration);
853
// handle properties/indexers
854
ResolveResult VisitPropertyMember(EntityDeclaration propertyOrIndexerDeclaration)
856
CSharpResolver oldResolver = resolver;
859
if (unresolvedFile != null) {
860
member = GetMemberFromLocation(propertyOrIndexerDeclaration);
862
// Re-discover the property:
863
string name = propertyOrIndexerDeclaration.Name;
864
var parameterTypeReferences = TypeSystemConvertVisitor.GetParameterTypes(propertyOrIndexerDeclaration.GetChildrenByRole(Roles.Parameter), InterningProvider.Dummy);
865
AstType explicitInterfaceAstType = propertyOrIndexerDeclaration.GetChildByRole(EntityDeclaration.PrivateImplementationTypeRole);
866
ITypeReference explicitInterfaceType = null;
867
if (!explicitInterfaceAstType.IsNull) {
868
explicitInterfaceType = explicitInterfaceAstType.ToTypeReference();
870
member = AbstractUnresolvedMember.Resolve(
871
resolver.CurrentTypeResolveContext, propertyOrIndexerDeclaration.EntityType, name,
872
explicitInterfaceType, parameterTypeReferences: parameterTypeReferences);
874
// We need to use the property as current member so that indexer parameters can be resolved correctly.
875
resolver = resolver.WithCurrentMember(member);
876
var resolverWithPropertyAsMember = resolver;
878
for (AstNode node = propertyOrIndexerDeclaration.FirstChild; node != null; node = node.NextSibling) {
879
if (node.Role == PropertyDeclaration.GetterRole && member is IProperty) {
880
resolver = resolver.WithCurrentMember(((IProperty)member).Getter);
882
resolver = resolverWithPropertyAsMember;
883
} else if (node.Role == PropertyDeclaration.SetterRole && member is IProperty) {
884
resolver = resolver.WithCurrentMember(((IProperty)member).Setter);
886
resolver = resolverWithPropertyAsMember;
892
return new MemberResolveResult(null, member, false);
896
resolver = oldResolver;
900
ResolveResult IAstVisitor<ResolveResult>.VisitPropertyDeclaration(PropertyDeclaration propertyDeclaration)
902
return VisitPropertyMember(propertyDeclaration);
905
ResolveResult IAstVisitor<ResolveResult>.VisitIndexerDeclaration(IndexerDeclaration indexerDeclaration)
907
return VisitPropertyMember(indexerDeclaration);
910
ResolveResult IAstVisitor<ResolveResult>.VisitCustomEventDeclaration(CustomEventDeclaration eventDeclaration)
912
CSharpResolver oldResolver = resolver;
915
if (unresolvedFile != null) {
916
member = GetMemberFromLocation(eventDeclaration);
918
string name = eventDeclaration.Name;
919
AstType explicitInterfaceAstType = eventDeclaration.PrivateImplementationType;
920
if (explicitInterfaceAstType.IsNull) {
921
member = AbstractUnresolvedMember.Resolve(resolver.CurrentTypeResolveContext, EntityType.Event, name);
923
member = AbstractUnresolvedMember.Resolve(resolver.CurrentTypeResolveContext, EntityType.Event, name,
924
explicitInterfaceAstType.ToTypeReference());
927
resolver = resolver.WithCurrentMember(member);
928
var resolverWithEventAsMember = resolver;
930
for (AstNode node = eventDeclaration.FirstChild; node != null; node = node.NextSibling) {
931
if (node.Role == CustomEventDeclaration.AddAccessorRole && member is IEvent) {
932
resolver = resolver.WithCurrentMember(((IEvent)member).AddAccessor);
934
resolver = resolverWithEventAsMember;
935
} else if (node.Role == CustomEventDeclaration.RemoveAccessorRole && member is IEvent) {
936
resolver = resolver.WithCurrentMember(((IEvent)member).RemoveAccessor);
938
resolver = resolverWithEventAsMember;
945
return new MemberResolveResult(null, member, false);
949
resolver = oldResolver;
953
ResolveResult IAstVisitor<ResolveResult>.VisitParameterDeclaration(ParameterDeclaration parameterDeclaration)
955
ScanChildren(parameterDeclaration);
956
if (resolverEnabled) {
957
string name = parameterDeclaration.Name;
959
if (parameterDeclaration.Parent is DocumentationReference) {
960
// create a dummy parameter
961
IType type = ResolveType(parameterDeclaration.Type);
962
switch (parameterDeclaration.ParameterModifier) {
963
case ParameterModifier.Ref:
964
case ParameterModifier.Out:
965
type = new ByReferenceType(type);
968
return new LocalResolveResult(new DefaultParameter(
970
isRef: parameterDeclaration.ParameterModifier == ParameterModifier.Ref,
971
isOut: parameterDeclaration.ParameterModifier == ParameterModifier.Out,
972
isParams: parameterDeclaration.ParameterModifier == ParameterModifier.Params));
975
// Look in lambda parameters:
976
foreach (IParameter p in resolver.LocalVariables.OfType<IParameter>()) {
978
return new LocalResolveResult(p);
981
IParameterizedMember pm = resolver.CurrentMember as IParameterizedMember;
982
if (pm == null && resolver.CurrentTypeDefinition != null) {
983
// Also consider delegate parameters:
984
pm = resolver.CurrentTypeDefinition.GetDelegateInvokeMethod();
985
// pm will be null if the current type isn't a delegate
988
foreach (IParameter p in pm.Parameters) {
989
if (p.Name == name) {
990
return new LocalResolveResult(p);
1001
ResolveResult IAstVisitor<ResolveResult>.VisitTypeParameterDeclaration(TypeParameterDeclaration typeParameterDeclaration)
1003
ScanChildren(typeParameterDeclaration);
1004
if (resolverEnabled) {
1005
string name = typeParameterDeclaration.Name;
1006
IMethod m = resolver.CurrentMember as IMethod;
1008
foreach (var tp in m.TypeParameters) {
1009
if (tp.Name == name)
1010
return new TypeResolveResult(tp);
1013
if (resolver.CurrentTypeDefinition != null) {
1014
var typeParameters = resolver.CurrentTypeDefinition.TypeParameters;
1015
// look backwards so that TPs in the current type take precedence over those copied from outer types
1016
for (int i = typeParameters.Count - 1; i >= 0; i--) {
1017
if (typeParameters[i].Name == name)
1018
return new TypeResolveResult(typeParameters[i]);
1027
ResolveResult IAstVisitor<ResolveResult>.VisitEnumMemberDeclaration(EnumMemberDeclaration enumMemberDeclaration)
1029
CSharpResolver oldResolver = resolver;
1031
// Scan enum member attributes before setting resolver.CurrentMember, so that
1032
// enum values used as attribute arguments have the correct type.
1033
// (within an enum member, all other enum members are treated as having their underlying type)
1034
foreach (var attributeSection in enumMemberDeclaration.Attributes)
1035
Scan(attributeSection);
1037
IMember member = null;
1038
if (unresolvedFile != null) {
1039
member = GetMemberFromLocation(enumMemberDeclaration);
1040
} else if (resolver.CurrentTypeDefinition != null) {
1041
string name = enumMemberDeclaration.Name;
1042
member = resolver.CurrentTypeDefinition.GetFields(f => f.Name == name, GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault();
1044
resolver = resolver.WithCurrentMember(member);
1046
if (resolverEnabled && resolver.CurrentTypeDefinition != null) {
1047
ResolveAndProcessConversion(enumMemberDeclaration.Initializer, resolver.CurrentTypeDefinition.EnumUnderlyingType);
1048
if (resolverEnabled && member != null)
1049
return new MemberResolveResult(null, member, false);
1053
Scan(enumMemberDeclaration.Initializer);
1057
resolver = oldResolver;
1062
#region Track CheckForOverflow
1063
ResolveResult IAstVisitor<ResolveResult>.VisitCheckedExpression(CheckedExpression checkedExpression)
1065
CSharpResolver oldResolver = resolver;
1067
resolver = resolver.WithCheckForOverflow(true);
1068
if (resolverEnabled) {
1069
return Resolve(checkedExpression.Expression);
1071
ScanChildren(checkedExpression);
1075
resolver = oldResolver;
1079
ResolveResult IAstVisitor<ResolveResult>.VisitUncheckedExpression(UncheckedExpression uncheckedExpression)
1081
CSharpResolver oldResolver = resolver;
1083
resolver = resolver.WithCheckForOverflow(false);
1084
if (resolverEnabled) {
1085
return Resolve(uncheckedExpression.Expression);
1087
ScanChildren(uncheckedExpression);
1091
resolver = oldResolver;
1095
ResolveResult IAstVisitor<ResolveResult>.VisitCheckedStatement(CheckedStatement checkedStatement)
1097
CSharpResolver oldResolver = resolver;
1099
resolver = resolver.WithCheckForOverflow(true);
1100
ScanChildren(checkedStatement);
1103
resolver = oldResolver;
1107
ResolveResult IAstVisitor<ResolveResult>.VisitUncheckedStatement(UncheckedStatement uncheckedStatement)
1109
CSharpResolver oldResolver = resolver;
1111
resolver = resolver.WithCheckForOverflow(false);
1112
ScanChildren(uncheckedStatement);
1115
resolver = oldResolver;
1120
#region Visit AnonymousTypeCreateExpression
1121
static string GetAnonymousTypePropertyName(Expression expr, out Expression resolveExpr)
1123
if (expr is NamedExpression) {
1124
var namedArgExpr = (NamedExpression)expr;
1125
resolveExpr = namedArgExpr.Expression;
1126
return namedArgExpr.Name;
1128
// no name given, so it's a projection initializer
1129
if (expr is MemberReferenceExpression) {
1131
return ((MemberReferenceExpression)expr).MemberName;
1133
if (expr is IdentifierExpression) {
1135
return ((IdentifierExpression)expr).Identifier;
1141
class AnonymousTypeMember
1143
public readonly Expression Expression;
1144
public readonly ResolveResult Initializer;
1146
public AnonymousTypeMember(Expression expression, ResolveResult initializer)
1148
this.Expression = expression;
1149
this.Initializer = initializer;
1153
ResolveResult IAstVisitor<ResolveResult>.VisitAnonymousTypeCreateExpression(AnonymousTypeCreateExpression anonymousTypeCreateExpression)
1155
// 7.6.10.6 Anonymous object creation expressions
1156
List<IUnresolvedProperty> unresolvedProperties = new List<IUnresolvedProperty>();
1157
List<AnonymousTypeMember> members = new List<AnonymousTypeMember>();
1158
foreach (var expr in anonymousTypeCreateExpression.Initializers) {
1159
Expression resolveExpr;
1160
var name = GetAnonymousTypePropertyName(expr, out resolveExpr);
1161
if (resolveExpr != null) {
1162
var initRR = Resolve(resolveExpr);
1163
var returnTypeRef = initRR.Type.ToTypeReference();
1164
var property = new DefaultUnresolvedProperty();
1165
property.Name = name;
1166
property.Accessibility = Accessibility.Public;
1167
property.ReturnType = returnTypeRef;
1168
property.Getter = new DefaultUnresolvedMethod {
1169
Name = "get_" + name,
1170
Accessibility = Accessibility.Public,
1171
ReturnType = returnTypeRef,
1172
EntityType = EntityType.Accessor,
1173
AccessorOwner = property
1175
unresolvedProperties.Add(property);
1176
members.Add(new AnonymousTypeMember(expr, initRR));
1181
var anonymousType = new AnonymousType(resolver.Compilation, unresolvedProperties);
1182
var properties = anonymousType.GetProperties().ToList();
1183
Debug.Assert(properties.Count == members.Count);
1184
List<ResolveResult> assignments = new List<ResolveResult>();
1185
for (int i = 0; i < members.Count; i++) {
1186
ResolveResult lhs = new MemberResolveResult(new InitializedObjectResolveResult(anonymousType), properties[i]);
1187
ResolveResult rhs = members[i].Initializer;
1188
ResolveResult assignment = resolver.ResolveAssignment(AssignmentOperatorType.Assign, lhs, rhs);
1189
var ne = members[i].Expression as NamedExpression;
1191
StoreCurrentState(ne);
1192
// ne.Expression was already resolved by the first loop
1193
StoreResult(ne, lhs);
1195
assignments.Add(assignment);
1197
var anonymousCtor = DefaultResolvedMethod.GetDummyConstructor(resolver.Compilation, anonymousType);
1198
return new InvocationResolveResult(null, anonymousCtor, initializerStatements: assignments);
1202
#region Visit Expressions
1203
ResolveResult IAstVisitor<ResolveResult>.VisitArrayCreateExpression(ArrayCreateExpression arrayCreateExpression)
1205
int dimensions = arrayCreateExpression.Arguments.Count;
1206
IEnumerable<Expression> sizeArgumentExpressions;
1207
ResolveResult[] sizeArguments;
1208
IEnumerable<ArraySpecifier> additionalArraySpecifiers;
1209
if (dimensions == 0) {
1210
var firstSpecifier = arrayCreateExpression.AdditionalArraySpecifiers.FirstOrDefault();
1211
if (firstSpecifier != null) {
1212
dimensions = firstSpecifier.Dimensions;
1213
additionalArraySpecifiers = arrayCreateExpression.AdditionalArraySpecifiers.Skip(1);
1216
additionalArraySpecifiers = arrayCreateExpression.AdditionalArraySpecifiers;
1218
sizeArguments = null;
1219
sizeArgumentExpressions = null;
1221
sizeArgumentExpressions = arrayCreateExpression.Arguments;
1222
sizeArguments = new ResolveResult[dimensions];
1224
foreach (var node in sizeArgumentExpressions)
1225
sizeArguments[pos++] = Resolve(node);
1226
additionalArraySpecifiers = arrayCreateExpression.AdditionalArraySpecifiers;
1230
List<Expression> initializerElements;
1231
ResolveResult[] initializerElementResults;
1232
if (arrayCreateExpression.Initializer.IsNull) {
1234
initializerElements = null;
1235
initializerElementResults = null;
1237
StoreCurrentState(arrayCreateExpression.Initializer);
1239
initializerElements = new List<Expression>();
1240
sizes = new int[dimensions];
1241
UnpackArrayInitializer(initializerElements, sizes, arrayCreateExpression.Initializer, 0, true);
1242
initializerElementResults = new ResolveResult[initializerElements.Count];
1243
for (int i = 0; i < initializerElementResults.Length; i++) {
1244
initializerElementResults[i] = Resolve(initializerElements[i]);
1246
StoreResult(arrayCreateExpression.Initializer, voidResult);
1250
if (arrayCreateExpression.Type.IsNull) {
1253
elementType = ResolveType(arrayCreateExpression.Type);
1254
foreach (var spec in additionalArraySpecifiers.Reverse()) {
1255
elementType = new ArrayType(resolver.Compilation, elementType, spec.Dimensions);
1258
ArrayCreateResolveResult acrr;
1259
if (sizeArguments != null) {
1260
acrr = resolver.ResolveArrayCreation(elementType, sizeArguments, initializerElementResults);
1261
} else if (sizes != null) {
1262
acrr = resolver.ResolveArrayCreation(elementType, sizes, initializerElementResults);
1264
// neither size arguments nor an initializer exist -> error
1265
return new ErrorResolveResult(new ArrayType(resolver.Compilation, elementType ?? SpecialType.UnknownType, dimensions));
1267
if (sizeArgumentExpressions != null)
1268
ProcessConversionResults(sizeArgumentExpressions, acrr.SizeArguments);
1269
if (acrr.InitializerElements != null)
1270
ProcessConversionResults(initializerElements, acrr.InitializerElements);
1274
void UnpackArrayInitializer(List<Expression> elementList, int[] sizes, ArrayInitializerExpression initializer, int dimension, bool resolveNestedInitializersToVoid)
1276
Debug.Assert(dimension < sizes.Length);
1277
int elementCount = 0;
1278
if (dimension + 1 < sizes.Length) {
1279
foreach (var node in initializer.Elements) {
1280
ArrayInitializerExpression aie = node as ArrayInitializerExpression;
1282
if (resolveNestedInitializersToVoid) {
1283
StoreCurrentState(aie);
1284
StoreResult(aie, voidResult);
1286
UnpackArrayInitializer(elementList, sizes, aie, dimension + 1, resolveNestedInitializersToVoid);
1288
elementList.Add(node);
1293
foreach (var expr in initializer.Elements) {
1294
elementList.Add(expr);
1298
if (sizes[dimension] == 0) // 0 = uninitialized
1299
sizes[dimension] = elementCount;
1300
else if (sizes[dimension] != elementCount)
1301
sizes[dimension] = -1; // -1 = error
1304
ResolveResult IAstVisitor<ResolveResult>.VisitArrayInitializerExpression(ArrayInitializerExpression arrayInitializerExpression)
1306
// Array initializers are handled by their parent expression.
1307
ScanChildren(arrayInitializerExpression);
1311
ResolveResult IAstVisitor<ResolveResult>.VisitAsExpression(AsExpression asExpression)
1313
if (resolverEnabled) {
1314
ResolveResult input = Resolve(asExpression.Expression);
1315
var targetType = ResolveType(asExpression.Type);
1316
return new ConversionResolveResult(targetType, input, Conversion.TryCast, resolver.CheckForOverflow);
1318
ScanChildren(asExpression);
1323
ResolveResult IAstVisitor<ResolveResult>.VisitAssignmentExpression(AssignmentExpression assignmentExpression)
1325
if (resolverEnabled) {
1326
Expression left = assignmentExpression.Left;
1327
Expression right = assignmentExpression.Right;
1328
ResolveResult leftResult = Resolve(left);
1329
ResolveResult rightResult = Resolve(right);
1330
ResolveResult rr = resolver.ResolveAssignment(assignmentExpression.Operator, leftResult, rightResult);
1331
ProcessConversionsInBinaryOperatorResult(left, right, rr);
1334
ScanChildren(assignmentExpression);
1339
ResolveResult IAstVisitor<ResolveResult>.VisitBaseReferenceExpression(BaseReferenceExpression baseReferenceExpression)
1341
if (resolverEnabled) {
1342
return resolver.ResolveBaseReference();
1344
ScanChildren(baseReferenceExpression);
1349
ResolveResult IAstVisitor<ResolveResult>.VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression)
1351
if (resolverEnabled) {
1352
Expression left = binaryOperatorExpression.Left;
1353
Expression right = binaryOperatorExpression.Right;
1354
ResolveResult leftResult = Resolve(left);
1355
ResolveResult rightResult = Resolve(right);
1356
ResolveResult rr = resolver.ResolveBinaryOperator(binaryOperatorExpression.Operator, leftResult, rightResult);
1357
ProcessConversionsInBinaryOperatorResult(left, right, rr);
1360
ScanChildren(binaryOperatorExpression);
1365
ResolveResult ProcessConversionsInBinaryOperatorResult(Expression left, Expression right, ResolveResult rr)
1367
OperatorResolveResult orr = rr as OperatorResolveResult;
1368
if (orr != null && orr.Operands.Count == 2) {
1369
ProcessConversionResult(left, orr.Operands[0] as ConversionResolveResult);
1370
ProcessConversionResult(right, orr.Operands[1] as ConversionResolveResult);
1372
InvocationResolveResult irr = rr as InvocationResolveResult;
1373
if (irr != null && irr.Arguments.Count == 2) {
1374
ProcessConversionResult(left, irr.Arguments[0] as ConversionResolveResult);
1375
ProcessConversionResult(right, irr.Arguments[1] as ConversionResolveResult);
1381
ResolveResult IAstVisitor<ResolveResult>.VisitCastExpression(CastExpression castExpression)
1383
if (resolverEnabled) {
1384
IType targetType = ResolveType(castExpression.Type);
1385
Expression expr = castExpression.Expression;
1386
ResolveResult rr = resolver.ResolveCast(targetType, Resolve(expr));
1387
ProcessConversionResult(expr, rr as ConversionResolveResult);
1390
ScanChildren(castExpression);
1395
ResolveResult IAstVisitor<ResolveResult>.VisitConditionalExpression(ConditionalExpression conditionalExpression)
1397
if (resolverEnabled) {
1398
Expression condition = conditionalExpression.Condition;
1399
Expression trueExpr = conditionalExpression.TrueExpression;
1400
Expression falseExpr = conditionalExpression.FalseExpression;
1402
ResolveResult rr = resolver.ResolveConditional(Resolve(condition), Resolve(trueExpr), Resolve(falseExpr));
1403
OperatorResolveResult corr = rr as OperatorResolveResult;
1404
if (corr != null && corr.Operands.Count == 3) {
1405
ProcessConversionResult(condition, corr.Operands[0] as ConversionResolveResult);
1406
ProcessConversionResult(trueExpr, corr.Operands[1] as ConversionResolveResult);
1407
ProcessConversionResult(falseExpr, corr.Operands[2] as ConversionResolveResult);
1411
ScanChildren(conditionalExpression);
1416
ResolveResult IAstVisitor<ResolveResult>.VisitDefaultValueExpression(DefaultValueExpression defaultValueExpression)
1418
if (resolverEnabled) {
1419
return resolver.ResolveDefaultValue(ResolveType(defaultValueExpression.Type));
1421
ScanChildren(defaultValueExpression);
1426
ResolveResult IAstVisitor<ResolveResult>.VisitDirectionExpression(DirectionExpression directionExpression)
1428
if (resolverEnabled) {
1429
ResolveResult rr = Resolve(directionExpression.Expression);
1430
return new ByReferenceResolveResult(rr, directionExpression.FieldDirection == FieldDirection.Out);
1432
ScanChildren(directionExpression);
1437
ResolveResult IAstVisitor<ResolveResult>.VisitEmptyExpression(EmptyExpression emptyExpression)
1442
ResolveResult IAstVisitor<ResolveResult>.VisitIndexerExpression(IndexerExpression indexerExpression)
1444
if (resolverEnabled || NeedsResolvingDueToNamedArguments(indexerExpression)) {
1445
Expression target = indexerExpression.Target;
1446
ResolveResult targetResult = Resolve(target);
1447
string[] argumentNames;
1448
ResolveResult[] arguments = GetArguments(indexerExpression.Arguments, out argumentNames);
1449
ResolveResult rr = resolver.ResolveIndexer(targetResult, arguments, argumentNames);
1450
ArrayAccessResolveResult aarr = rr as ArrayAccessResolveResult;
1452
MarkUnknownNamedArguments(indexerExpression.Arguments);
1453
ProcessConversionResults(indexerExpression.Arguments, aarr.Indexes);
1455
ProcessInvocationResult(target, indexerExpression.Arguments, rr);
1459
ScanChildren(indexerExpression);
1464
ResolveResult IAstVisitor<ResolveResult>.VisitIsExpression(IsExpression isExpression)
1466
if (resolverEnabled) {
1467
ResolveResult input = Resolve(isExpression.Expression);
1468
IType targetType = ResolveType(isExpression.Type);
1469
IType booleanType = resolver.Compilation.FindType(KnownTypeCode.Boolean);
1470
return new TypeIsResolveResult(input, targetType, booleanType);
1472
ScanChildren(isExpression);
1477
// NamedArgumentExpression is "identifier: Expression"
1478
ResolveResult IAstVisitor<ResolveResult>.VisitNamedArgumentExpression(NamedArgumentExpression namedArgumentExpression)
1480
// The parent expression takes care of handling NamedArgumentExpressions
1481
// by calling GetArguments().
1482
// This method gets called only when scanning, or when the named argument is used
1483
// in an invalid context.
1484
if (resolverEnabled) {
1485
return new NamedArgumentResolveResult(namedArgumentExpression.Name, Resolve(namedArgumentExpression.Expression));
1487
Scan(namedArgumentExpression.Expression);
1492
// NamedExpression is "identifier = Expression" in object initializers and attributes
1493
ResolveResult IAstVisitor<ResolveResult>.VisitNamedExpression(NamedExpression namedExpression)
1495
// The parent expression takes care of handling NamedExpression
1496
// by calling HandleObjectInitializer() or HandleNamedExpression().
1497
// This method gets called only when scanning, or when the named expression is used
1498
// in an invalid context.
1499
ScanChildren(namedExpression);
1503
void HandleNamedExpression(NamedExpression namedExpression, List<ResolveResult> initializerStatements)
1505
StoreCurrentState(namedExpression);
1506
Expression rhs = namedExpression.Expression;
1507
ResolveResult lhsRR = resolver.ResolveIdentifierInObjectInitializer(namedExpression.Name);
1508
if (rhs is ArrayInitializerExpression) {
1509
HandleObjectInitializer(lhsRR, (ArrayInitializerExpression)rhs, initializerStatements);
1511
var rhsRR = Resolve(rhs);
1512
var rr = resolver.ResolveAssignment(AssignmentOperatorType.Assign, lhsRR, rhsRR) as OperatorResolveResult;
1514
ProcessConversionResult(rhs, rr.Operands[1] as ConversionResolveResult);
1515
initializerStatements.Add(rr);
1518
StoreResult(namedExpression, lhsRR);
1521
ResolveResult IAstVisitor<ResolveResult>.VisitNullReferenceExpression(NullReferenceExpression nullReferenceExpression)
1523
return resolver.ResolvePrimitive(null);
1526
ResolveResult IAstVisitor<ResolveResult>.VisitObjectCreateExpression(ObjectCreateExpression objectCreateExpression)
1528
var typeResolveResult = Resolve(objectCreateExpression.Type);
1529
if (typeResolveResult.IsError) {
1530
ScanChildren (objectCreateExpression);
1531
return typeResolveResult;
1533
IType type = typeResolveResult.Type;
1535
List<ResolveResult> initializerStatements = null;
1536
var initializer = objectCreateExpression.Initializer;
1537
if (!initializer.IsNull) {
1538
initializerStatements = new List<ResolveResult>();
1539
HandleObjectInitializer(new InitializedObjectResolveResult(type), initializer, initializerStatements);
1542
string[] argumentNames;
1543
ResolveResult[] arguments = GetArguments(objectCreateExpression.Arguments, out argumentNames);
1545
ResolveResult rr = resolver.ResolveObjectCreation(type, arguments, argumentNames, false, initializerStatements);
1546
if (arguments.Length == 1 && rr.Type.Kind == TypeKind.Delegate) {
1547
MarkUnknownNamedArguments(objectCreateExpression.Arguments);
1548
// Apply conversion to argument if it directly wraps the argument
1549
// (but not when creating a delegate from a delegate, as then there would be a MGRR for .Invoke in between)
1550
// This is necessary for lambda type inference.
1551
var crr = rr as ConversionResolveResult;
1552
if (crr != null && crr.Input == arguments[0]) {
1553
ProcessConversionResult(objectCreateExpression.Arguments.Single(), crr);
1555
// wrap the result so that the delegate creation is not handled as a reference
1556
// to the target method - otherwise FindReferencedEntities would produce two results for
1557
// the same delegate creation.
1558
return WrapResult(rr);
1563
// process conversions in all other cases
1564
ProcessInvocationResult(null, objectCreateExpression.Arguments, rr);
1569
void HandleObjectInitializer(ResolveResult initializedObject, ArrayInitializerExpression initializer, List<ResolveResult> initializerStatements)
1571
StoreCurrentState(initializer);
1572
resolver = resolver.PushObjectInitializer(initializedObject);
1573
foreach (Expression element in initializer.Elements) {
1574
ArrayInitializerExpression aie = element as ArrayInitializerExpression;
1576
StoreCurrentState(aie);
1577
// constructor argument list in collection initializer
1578
ResolveResult[] addArguments = new ResolveResult[aie.Elements.Count];
1580
foreach (var addArgument in aie.Elements) {
1581
addArguments[i++] = Resolve(addArgument);
1583
MemberLookup memberLookup = resolver.CreateMemberLookup();
1584
var addRR = memberLookup.Lookup(initializedObject, "Add", EmptyList<IType>.Instance, true);
1585
var mgrr = addRR as MethodGroupResolveResult;
1587
OverloadResolution or = mgrr.PerformOverloadResolution(resolver.Compilation, addArguments, null, false, false, false, resolver.CheckForOverflow, resolver.conversions);
1588
var invocationRR = or.CreateResolveResult(initializedObject);
1589
StoreResult(aie, invocationRR);
1590
ProcessInvocationResult(null, aie.Elements, invocationRR);
1591
initializerStatements.Add(invocationRR);
1593
StoreResult(aie, addRR);
1595
} else if (element is NamedExpression) {
1596
HandleNamedExpression((NamedExpression)element, initializerStatements);
1598
// unknown kind of expression
1602
resolver = resolver.PopObjectInitializer();
1603
StoreResult(initializer, voidResult);
1606
ResolveResult IAstVisitor<ResolveResult>.VisitParenthesizedExpression(ParenthesizedExpression parenthesizedExpression)
1608
if (resolverEnabled) {
1609
return Resolve(parenthesizedExpression.Expression);
1611
Scan(parenthesizedExpression.Expression);
1616
ResolveResult IAstVisitor<ResolveResult>.VisitPointerReferenceExpression(PointerReferenceExpression pointerReferenceExpression)
1618
if (resolverEnabled) {
1619
ResolveResult target = Resolve(pointerReferenceExpression.Target);
1620
ResolveResult deferencedTarget = resolver.ResolveUnaryOperator(UnaryOperatorType.Dereference, target);
1621
List<IType> typeArguments = new List<IType>();
1622
foreach (AstType typeArgument in pointerReferenceExpression.TypeArguments) {
1623
typeArguments.Add(ResolveType(typeArgument));
1625
return resolver.ResolveMemberAccess(deferencedTarget, pointerReferenceExpression.MemberName,
1627
GetNameLookupMode(pointerReferenceExpression));
1629
ScanChildren(pointerReferenceExpression);
1634
ResolveResult IAstVisitor<ResolveResult>.VisitPrimitiveExpression(PrimitiveExpression primitiveExpression)
1636
return resolver.ResolvePrimitive(primitiveExpression.Value);
1639
ResolveResult IAstVisitor<ResolveResult>.VisitSizeOfExpression(SizeOfExpression sizeOfExpression)
1641
return resolver.ResolveSizeOf(ResolveType(sizeOfExpression.Type));
1644
ResolveResult IAstVisitor<ResolveResult>.VisitStackAllocExpression(StackAllocExpression stackAllocExpression)
1646
ResolveAndProcessConversion(stackAllocExpression.CountExpression, resolver.Compilation.FindType(KnownTypeCode.Int32));
1647
return new ResolveResult(new PointerType(ResolveType(stackAllocExpression.Type)));
1650
ResolveResult IAstVisitor<ResolveResult>.VisitThisReferenceExpression(ThisReferenceExpression thisReferenceExpression)
1652
return resolver.ResolveThisReference();
1655
ResolveResult IAstVisitor<ResolveResult>.VisitTypeOfExpression(TypeOfExpression typeOfExpression)
1657
if (resolverEnabled) {
1658
return resolver.ResolveTypeOf(ResolveType(typeOfExpression.Type));
1660
Scan(typeOfExpression.Type);
1665
ResolveResult IAstVisitor<ResolveResult>.VisitTypeReferenceExpression(TypeReferenceExpression typeReferenceExpression)
1667
if (resolverEnabled) {
1668
return Resolve(typeReferenceExpression.Type).ShallowClone();
1670
Scan(typeReferenceExpression.Type);
1675
ResolveResult IAstVisitor<ResolveResult>.VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression)
1677
if (resolverEnabled) {
1678
Expression expr = unaryOperatorExpression.Expression;
1679
ResolveResult input = Resolve(expr);
1680
ITypeDefinition inputTypeDef = input.Type.GetDefinition();
1681
if (input.IsCompileTimeConstant && expr is PrimitiveExpression && inputTypeDef != null) {
1682
// Special cases for int.MinValue and long.MinValue
1683
if (inputTypeDef.KnownTypeCode == KnownTypeCode.UInt32 && 2147483648.Equals(input.ConstantValue)) {
1684
return new ConstantResolveResult(resolver.Compilation.FindType(KnownTypeCode.Int32), -2147483648);
1685
} else if (inputTypeDef.KnownTypeCode == KnownTypeCode.UInt64 && 9223372036854775808.Equals(input.ConstantValue)) {
1686
return new ConstantResolveResult(resolver.Compilation.FindType(KnownTypeCode.Int64), -9223372036854775808);
1689
ResolveResult rr = resolver.ResolveUnaryOperator(unaryOperatorExpression.Operator, input);
1690
OperatorResolveResult uorr = rr as OperatorResolveResult;
1691
if (uorr != null && uorr.Operands.Count == 1) {
1692
ProcessConversionResult(expr, uorr.Operands[0] as ConversionResolveResult);
1694
InvocationResolveResult irr = rr as InvocationResolveResult;
1695
if (irr != null && irr.Arguments.Count == 1) {
1696
ProcessConversionResult(expr, irr.Arguments[0] as ConversionResolveResult);
1701
ScanChildren(unaryOperatorExpression);
1706
ResolveResult IAstVisitor<ResolveResult>.VisitUndocumentedExpression(UndocumentedExpression undocumentedExpression)
1708
ScanChildren(undocumentedExpression);
1710
switch (undocumentedExpression.UndocumentedExpressionType) {
1711
case UndocumentedExpressionType.ArgListAccess:
1712
case UndocumentedExpressionType.ArgList:
1713
resultType = resolver.Compilation.FindType(typeof(RuntimeArgumentHandle));
1715
case UndocumentedExpressionType.RefValue:
1716
var tre = undocumentedExpression.Arguments.ElementAtOrDefault(1) as TypeReferenceExpression;
1718
resultType = ResolveType(tre.Type);
1720
resultType = SpecialType.UnknownType;
1722
case UndocumentedExpressionType.RefType:
1723
resultType = resolver.Compilation.FindType(KnownTypeCode.Type);
1725
case UndocumentedExpressionType.MakeRef:
1726
resultType = resolver.Compilation.FindType(typeof(TypedReference));
1729
throw new InvalidOperationException("Invalid value for UndocumentedExpressionType");
1731
return new ResolveResult(resultType);
1735
#region Visit Identifier/MemberReference/Invocation-Expression
1736
// IdentifierExpression, MemberReferenceExpression and InvocationExpression
1737
// are grouped together because they have to work together for
1738
// "7.6.4.1 Identical simple names and type names" support
1739
List<IType> ResolveTypeArguments(IEnumerable<AstType> typeArguments)
1741
List<IType> result = new List<IType>();
1742
foreach (AstType typeArgument in typeArguments) {
1743
result.Add(ResolveType(typeArgument));
1749
/// Gets and resolves the arguments; unpacking any NamedArgumentExpressions.
1752
/// Callers of GetArguments must also call either ProcessConversionsInInvocation or MarkUnknownNamedArguments
1753
/// to ensure the named arguments get resolved.
1754
/// Also, as named arguments get resolved by the parent node, the parent node must not scan
1755
/// into the argument list without being resolved - see NeedsResolvingDueToNamedArguments().
1757
ResolveResult[] GetArguments(IEnumerable<Expression> argumentExpressions, out string[] argumentNames)
1759
argumentNames = null;
1760
ResolveResult[] arguments = new ResolveResult[argumentExpressions.Count()];
1762
foreach (AstNode argument in argumentExpressions) {
1763
NamedArgumentExpression nae = argument as NamedArgumentExpression;
1764
AstNode argumentValue;
1766
if (argumentNames == null)
1767
argumentNames = new string[arguments.Length];
1768
argumentNames[i] = nae.Name;
1769
argumentValue = nae.Expression;
1771
argumentValue = argument;
1773
arguments[i++] = Resolve(argumentValue);
1778
bool NeedsResolvingDueToNamedArguments(Expression nodeWithArguments)
1780
for (AstNode child = nodeWithArguments.FirstChild; child != null; child = child.NextSibling) {
1781
if (child is NamedArgumentExpression)
1787
static NameLookupMode GetNameLookupMode(Expression expr)
1789
InvocationExpression ie = expr.Parent as InvocationExpression;
1790
if (ie != null && ie.Target == expr)
1791
return NameLookupMode.InvocationTarget;
1793
return NameLookupMode.Expression;
1797
/// Gets whether 'rr' is considered a static access on the target identifier.
1799
/// <param name="rr">Resolve Result of the MemberReferenceExpression</param>
1800
/// <param name="invocationRR">Resolve Result of the InvocationExpression</param>
1801
bool IsStaticResult(ResolveResult rr, ResolveResult invocationRR)
1803
if (rr is TypeResolveResult)
1805
MemberResolveResult mrr = (rr is MethodGroupResolveResult ? invocationRR : rr) as MemberResolveResult;
1806
return mrr != null && mrr.Member.IsStatic;
1809
ResolveResult IAstVisitor<ResolveResult>.VisitIdentifierExpression(IdentifierExpression identifierExpression)
1811
// Note: this method is not called when it occurs in a situation where an ambiguity between
1812
// simple names and type names might occur.
1813
if (resolverEnabled) {
1814
var typeArguments = ResolveTypeArguments(identifierExpression.TypeArguments);
1815
var lookupMode = GetNameLookupMode(identifierExpression);
1816
return resolver.LookupSimpleNameOrTypeName(
1817
identifierExpression.Identifier, typeArguments, lookupMode);
1819
ScanChildren(identifierExpression);
1824
ResolveResult IAstVisitor<ResolveResult>.VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression)
1826
// target = Resolve(identifierExpression = memberReferenceExpression.Target)
1827
// trr = ResolveType(identifierExpression)
1828
// rr = Resolve(memberReferenceExpression)
1830
IdentifierExpression identifierExpression = memberReferenceExpression.Target as IdentifierExpression;
1831
if (identifierExpression != null && identifierExpression.TypeArguments.Count == 0) {
1832
// Special handling for Ā§7.6.4.1 Identicial simple names and type names
1833
StoreCurrentState(identifierExpression);
1834
ResolveResult target = resolver.ResolveSimpleName(identifierExpression.Identifier, EmptyList<IType>.Instance);
1835
TypeResolveResult trr;
1836
if (resolver.IsVariableReferenceWithSameType(target, identifierExpression.Identifier, out trr)) {
1838
ResolveResult rr = ResolveMemberReferenceOnGivenTarget(target, memberReferenceExpression);
1839
ResolveResult simpleNameRR = IsStaticResult(rr, null) ? trr : target;
1840
Log.WriteLine("Ambiguous simple name '{0}' was resolved to {1}", identifierExpression, simpleNameRR);
1841
StoreResult(identifierExpression, simpleNameRR);
1844
// It's not ambiguous
1845
Log.WriteLine("Simple name '{0}' was resolved to {1}", identifierExpression, target);
1846
StoreResult(identifierExpression, target);
1847
return ResolveMemberReferenceOnGivenTarget(target, memberReferenceExpression);
1850
// Regular code path
1851
if (resolverEnabled) {
1852
ResolveResult target = Resolve(memberReferenceExpression.Target);
1853
return ResolveMemberReferenceOnGivenTarget(target, memberReferenceExpression);
1855
ScanChildren(memberReferenceExpression);
1861
ResolveResult ResolveMemberReferenceOnGivenTarget(ResolveResult target, MemberReferenceExpression memberReferenceExpression)
1863
var typeArguments = ResolveTypeArguments(memberReferenceExpression.TypeArguments);
1864
return resolver.ResolveMemberAccess(
1865
target, memberReferenceExpression.MemberName, typeArguments,
1866
GetNameLookupMode(memberReferenceExpression));
1869
ResolveResult IAstVisitor<ResolveResult>.VisitInvocationExpression(InvocationExpression invocationExpression)
1871
// rr = Resolve(invocationExpression)
1872
// target = Resolve(memberReferenceExpression = invocationExpression.Target)
1873
// idRR = Resolve(identifierExpression = memberReferenceExpression.Target)
1874
// trr = ResolveType(identifierExpression)
1876
MemberReferenceExpression mre = invocationExpression.Target as MemberReferenceExpression;
1877
IdentifierExpression identifierExpression = mre != null ? mre.Target as IdentifierExpression : null;
1878
if (identifierExpression != null && identifierExpression.TypeArguments.Count == 0) {
1879
// Special handling for Ā§7.6.4.1 Identicial simple names and type names
1881
StoreCurrentState(identifierExpression);
1882
StoreCurrentState(mre);
1884
ResolveResult idRR = resolver.ResolveSimpleName(identifierExpression.Identifier, EmptyList<IType>.Instance);
1885
ResolveResult target = ResolveMemberReferenceOnGivenTarget(idRR, mre);
1886
Log.WriteLine("Member reference '{0}' on potentially-ambiguous simple-name was resolved to {1}", mre, target);
1887
StoreResult(mre, target);
1888
TypeResolveResult trr;
1889
if (resolver.IsVariableReferenceWithSameType(idRR, identifierExpression.Identifier, out trr)) {
1891
ResolveResult rr = ResolveInvocationOnGivenTarget(target, invocationExpression);
1892
ResolveResult simpleNameRR = IsStaticResult(target, rr) ? trr : idRR;
1893
Log.WriteLine("Ambiguous simple name '{0}' was resolved to {1}",
1894
identifierExpression, simpleNameRR);
1895
StoreResult(identifierExpression, simpleNameRR);
1898
// It's not ambiguous
1899
Log.WriteLine("Simple name '{0}' was resolved to {1}", identifierExpression, idRR);
1900
StoreResult(identifierExpression, idRR);
1901
return ResolveInvocationOnGivenTarget(target, invocationExpression);
1904
// Regular code path
1905
if (resolverEnabled || NeedsResolvingDueToNamedArguments(invocationExpression)) {
1906
ResolveResult target = Resolve(invocationExpression.Target);
1907
return ResolveInvocationOnGivenTarget(target, invocationExpression);
1909
ScanChildren(invocationExpression);
1915
ResolveResult ResolveInvocationOnGivenTarget(ResolveResult target, InvocationExpression invocationExpression)
1917
string[] argumentNames;
1918
ResolveResult[] arguments = GetArguments(invocationExpression.Arguments, out argumentNames);
1919
ResolveResult rr = resolver.ResolveInvocation(target, arguments, argumentNames);
1920
ProcessInvocationResult(invocationExpression.Target, invocationExpression.Arguments, rr);
1925
#region Lamdbas / Anonymous Functions
1926
ResolveResult IAstVisitor<ResolveResult>.VisitAnonymousMethodExpression(AnonymousMethodExpression anonymousMethodExpression)
1928
return HandleExplicitlyTypedLambda(
1929
anonymousMethodExpression.Parameters, anonymousMethodExpression.Body,
1930
isAnonymousMethod: true,
1931
hasParameterList: anonymousMethodExpression.HasParameterList,
1932
isAsync: anonymousMethodExpression.IsAsync);
1935
ResolveResult IAstVisitor<ResolveResult>.VisitLambdaExpression(LambdaExpression lambdaExpression)
1937
bool isExplicitlyTyped = false;
1938
bool isImplicitlyTyped = false;
1939
foreach (var p in lambdaExpression.Parameters) {
1940
isImplicitlyTyped |= p.Type.IsNull;
1941
isExplicitlyTyped |= !p.Type.IsNull;
1943
if (isExplicitlyTyped || !isImplicitlyTyped) {
1944
return HandleExplicitlyTypedLambda(
1945
lambdaExpression.Parameters, lambdaExpression.Body,
1946
isAnonymousMethod: false, hasParameterList: true, isAsync: lambdaExpression.IsAsync);
1948
return new ImplicitlyTypedLambda(lambdaExpression, this);
1952
#region Explicitly typed
1953
ExplicitlyTypedLambda HandleExplicitlyTypedLambda(
1954
AstNodeCollection<ParameterDeclaration> parameterDeclarations,
1955
AstNode body, bool isAnonymousMethod, bool hasParameterList, bool isAsync)
1957
CSharpResolver oldResolver = resolver;
1958
List<IParameter> parameters = (hasParameterList || parameterDeclarations.Any()) ? new List<IParameter>() : null;
1959
//bool oldIsWithinLambdaExpression = resolver.IsWithinLambdaExpression;
1960
resolver = resolver.WithIsWithinLambdaExpression(true);
1961
foreach (var pd in parameterDeclarations) {
1962
IType type = ResolveType(pd.Type);
1963
if (pd.ParameterModifier == ParameterModifier.Ref || pd.ParameterModifier == ParameterModifier.Out)
1964
type = new ByReferenceType(type);
1966
IParameter p = new DefaultParameter(type, pd.Name, MakeRegion(pd),
1967
isRef: pd.ParameterModifier == ParameterModifier.Ref,
1968
isOut: pd.ParameterModifier == ParameterModifier.Out);
1969
// The parameter declaration must be scanned in the current context (without the new parameter)
1970
// in order to be consistent with the context in which we resolved pd.Type.
1971
StoreCurrentState(pd);
1972
StoreResult(pd, new LocalResolveResult(p));
1975
resolver = resolver.AddVariable(p);
1979
var lambda = new ExplicitlyTypedLambda(parameters, isAnonymousMethod, isAsync, resolver, this, body);
1981
// Don't scan the lambda body here - we'll do that later when analyzing the ExplicitlyTypedLambda.
1983
resolver = oldResolver;
1987
DomRegion MakeRegion(AstNode node)
1989
if (unresolvedFile != null)
1990
return new DomRegion(unresolvedFile.FileName, node.StartLocation, node.EndLocation);
1992
return node.GetRegion();
1995
sealed class ExplicitlyTypedLambda : LambdaBase
1997
readonly IList<IParameter> parameters;
1998
readonly bool isAnonymousMethod;
1999
readonly bool isAsync;
2001
CSharpResolver storedContext;
2002
ResolveVisitor visitor;
2004
ResolveResult bodyRR;
2006
IType inferredReturnType;
2007
IList<Expression> returnExpressions;
2008
IList<ResolveResult> returnValues;
2009
bool isValidAsVoidMethod;
2010
bool isEndpointUnreachable;
2012
// The actual return type is set when the lambda is applied by the conversion.
2013
// For async lambdas, this is the unpacked task type
2014
IType actualReturnType;
2016
internal override bool IsUndecided {
2017
get { return actualReturnType == null; }
2020
internal override AstNode LambdaExpression {
2021
get { return body.Parent; }
2024
internal override AstNode BodyExpression {
2025
get { return body; }
2028
public override ResolveResult Body {
2033
if (body is Expression) {
2035
if (returnValues.Count == 1) {
2036
bodyRR = returnValues[0];
2037
if (actualReturnType.Kind != TypeKind.Void) {
2038
var conv = storedContext.conversions.ImplicitConversion(bodyRR, actualReturnType);
2039
if (!conv.IsIdentityConversion)
2040
bodyRR = new ConversionResolveResult(actualReturnType, bodyRR, conv, storedContext.CheckForOverflow);
2045
return bodyRR = visitor.voidResult;
2049
public ExplicitlyTypedLambda(IList<IParameter> parameters, bool isAnonymousMethod, bool isAsync, CSharpResolver storedContext, ResolveVisitor visitor, AstNode body)
2051
this.parameters = parameters;
2052
this.isAnonymousMethod = isAnonymousMethod;
2053
this.isAsync = isAsync;
2054
this.storedContext = storedContext;
2055
this.visitor = visitor;
2058
if (visitor.undecidedLambdas == null)
2059
visitor.undecidedLambdas = new List<LambdaBase>();
2060
visitor.undecidedLambdas.Add(this);
2061
Log.WriteLine("Added undecided explicitly-typed lambda: " + this.LambdaExpression);
2064
public override IList<IParameter> Parameters {
2066
return parameters ?? EmptyList<IParameter>.Instance;
2072
// If it's not already analyzed
2073
if (inferredReturnType == null) {
2074
Log.WriteLine("Analyzing " + this.LambdaExpression + "...");
2077
visitor.ResetContext(
2080
var oldNavigator = visitor.navigator;
2081
visitor.navigator = new ConstantModeResolveVisitorNavigator(ResolveVisitorNavigationMode.Resolve, oldNavigator);
2082
visitor.AnalyzeLambda(body, isAsync, out isValidAsVoidMethod, out isEndpointUnreachable, out inferredReturnType, out returnExpressions, out returnValues);
2083
visitor.navigator = oldNavigator;
2086
Log.WriteLine("Finished analyzing " + this.LambdaExpression);
2088
if (inferredReturnType == null)
2089
throw new InvalidOperationException("AnalyzeLambda() didn't set inferredReturnType");
2094
public override Conversion IsValid(IType[] parameterTypes, IType returnType, CSharpConversions conversions)
2096
Log.WriteLine("Testing validity of {0} for return-type {1}...", this, returnType);
2098
bool valid = Analyze() && IsValidLambda(isValidAsVoidMethod, isEndpointUnreachable, isAsync, returnValues, returnType, conversions);
2100
Log.WriteLine("{0} is {1} for return-type {2}", this, valid ? "valid" : "invalid", returnType);
2101
return new AnonymousFunctionConversion(returnType, this, valid);
2104
public override IType GetInferredReturnType(IType[] parameterTypes)
2107
return inferredReturnType;
2110
public override bool IsImplicitlyTyped {
2111
get { return false; }
2114
public override bool IsAsync {
2115
get { return isAsync; }
2118
public override bool IsAnonymousMethod {
2119
get { return isAnonymousMethod; }
2122
public override bool HasParameterList {
2123
get { return parameters != null; }
2126
public override string ToString()
2128
return "[ExplicitlyTypedLambda " + this.LambdaExpression + "]";
2131
public void ApplyReturnType(ResolveVisitor parentVisitor, IType returnType)
2133
if (returnType == null)
2134
throw new ArgumentNullException("returnType");
2135
if (parentVisitor != visitor) {
2136
// Explicitly typed lambdas do not use a nested visitor
2137
throw new InvalidOperationException();
2140
returnType = parentVisitor.UnpackTask(returnType);
2141
if (actualReturnType != null) {
2142
if (actualReturnType.Equals(returnType))
2143
return; // return type already set
2144
throw new InvalidOperationException("inconsistent return types for explicitly-typed lambda");
2146
actualReturnType = returnType;
2147
visitor.undecidedLambdas.Remove(this);
2149
Log.WriteLine("Applying return type {0} to explicitly-typed lambda {1}", returnType, this.LambdaExpression);
2150
if (returnType.Kind != TypeKind.Void) {
2151
for (int i = 0; i < returnExpressions.Count; i++) {
2152
visitor.ProcessConversion(returnExpressions[i], returnValues[i], returnType);
2157
internal override void EnforceMerge(ResolveVisitor parentVisitor)
2159
ApplyReturnType(parentVisitor, SpecialType.UnknownType);
2164
#region Implicitly typed
2165
// Implicitly-typed lambdas are really complex, as the lambda depends on the target type (the delegate to which
2166
// the lambda is converted), but figuring out the target type might involve overload resolution (for method
2167
// calls in which the lambda is used as argument), which requires knowledge about the lamdba.
2169
// The implementation in NRefactory works like this:
2170
// 1. The lambda resolves to a ImplicitlyTypedLambda (derived from LambdaResolveResult).
2171
// The lambda body is not resolved yet (one of the few places where ResolveVisitor
2172
// deviates from the usual depth-first AST traversal).
2173
// 2. The parent statement is resolved as usual. This might require analyzing the lambda in detail (for example
2174
// as part of overload resolution). Such analysis happens using LambdaResolveResult.IsValid, where the caller
2175
// (i.e. the overload resolution algorithm) supplies the parameter types to the lambda body. For every IsValid()
2176
// call, a nested LambdaTypeHypothesis is constructed for analyzing the lambda using the supplied type assignment.
2177
// Multiple IsValid() calls may use several LambdaTypeHypothesis instances, one for each set of parameter types.
2178
// 3. When the resolver reports the conversions that occurred as part of the parent statement (as with any
2179
// conversions), the results from the LambdaTypeHypothesis corresponding to the actually chosen
2180
// conversion are merged into the main resolver.
2181
// 4. LambdaResolveResult.Body is set to the main resolve result from the chosen nested resolver. I think this
2182
// is the only place where NRefactory is mutating a ResolveResult (normally all resolve results are immutable).
2183
// As this step is guaranteed to occur before the resolver returns the LamdbaResolveResult to user code, the
2184
// mutation shouldn't cause any problems.
2185
sealed class ImplicitlyTypedLambda : LambdaBase
2187
readonly LambdaExpression lambda;
2188
readonly QuerySelectClause selectClause;
2190
readonly CSharpResolver storedContext;
2191
readonly CSharpUnresolvedFile unresolvedFile;
2192
readonly List<LambdaTypeHypothesis> hypotheses = new List<LambdaTypeHypothesis>();
2193
internal IList<IParameter> parameters = new List<IParameter>();
2195
internal LambdaTypeHypothesis winningHypothesis;
2196
internal ResolveResult bodyResult;
2197
internal readonly ResolveVisitor parentVisitor;
2199
internal override bool IsUndecided {
2200
get { return winningHypothesis == null; }
2203
internal override AstNode LambdaExpression {
2205
if (selectClause != null)
2206
return selectClause.Expression;
2212
internal override AstNode BodyExpression {
2214
if (selectClause != null)
2215
return selectClause.Expression;
2221
public override ResolveResult Body {
2222
get { return bodyResult; }
2225
private ImplicitlyTypedLambda(ResolveVisitor parentVisitor)
2227
this.parentVisitor = parentVisitor;
2228
this.storedContext = parentVisitor.resolver;
2229
this.unresolvedFile = parentVisitor.unresolvedFile;
2230
this.bodyResult = parentVisitor.voidResult;
2233
public ImplicitlyTypedLambda(LambdaExpression lambda, ResolveVisitor parentVisitor)
2234
: this(parentVisitor)
2236
this.lambda = lambda;
2237
foreach (var pd in lambda.Parameters) {
2238
parameters.Add(new DefaultParameter(SpecialType.UnknownType, pd.Name, parentVisitor.MakeRegion(pd)));
2240
RegisterUndecidedLambda();
2243
public ImplicitlyTypedLambda(QuerySelectClause selectClause, IEnumerable<IParameter> parameters, ResolveVisitor parentVisitor)
2244
: this(parentVisitor)
2246
this.selectClause = selectClause;
2247
foreach (IParameter p in parameters)
2248
this.parameters.Add(p);
2250
RegisterUndecidedLambda();
2253
void RegisterUndecidedLambda()
2255
if (parentVisitor.undecidedLambdas == null)
2256
parentVisitor.undecidedLambdas = new List<LambdaBase>();
2257
parentVisitor.undecidedLambdas.Add(this);
2258
Log.WriteLine("Added undecided implicitly-typed lambda: " + this.LambdaExpression);
2261
public override IList<IParameter> Parameters {
2262
get { return parameters; }
2265
public override Conversion IsValid(IType[] parameterTypes, IType returnType, CSharpConversions conversions)
2267
Log.WriteLine("Testing validity of {0} for parameters ({1}) and return-type {2}...",
2268
this, string.Join<IType>(", ", parameterTypes), returnType);
2270
var hypothesis = GetHypothesis(parameterTypes);
2271
Conversion c = hypothesis.IsValid(returnType, conversions);
2273
Log.WriteLine("{0} is {1} for return-type {2}", hypothesis, c.IsValid ? "valid" : "invalid", returnType);
2277
public override IType GetInferredReturnType(IType[] parameterTypes)
2279
return GetHypothesis(parameterTypes).inferredReturnType;
2282
LambdaTypeHypothesis GetHypothesis(IType[] parameterTypes)
2284
if (parameterTypes.Length != parameters.Count)
2285
throw new ArgumentException("Incorrect parameter type count");
2286
foreach (var h in hypotheses) {
2288
for (int i = 0; i < parameterTypes.Length; i++) {
2289
if (!parameterTypes[i].Equals(h.parameterTypes[i])) {
2297
ResolveVisitor visitor = new ResolveVisitor(storedContext, unresolvedFile);
2298
var newHypothesis = new LambdaTypeHypothesis(this, parameterTypes, visitor, lambda != null ? lambda.Parameters : null, storedContext);
2299
hypotheses.Add(newHypothesis);
2300
return newHypothesis;
2304
/// Get any hypothesis for this lambda.
2305
/// This method is used as fallback if the lambda isn't merged the normal way (AnonymousFunctionConversion)
2307
internal LambdaTypeHypothesis GetAnyHypothesis()
2309
if (winningHypothesis != null)
2310
return winningHypothesis;
2311
if (hypotheses.Count == 0) {
2312
// make a new hypothesis with unknown parameter types
2313
IType[] parameterTypes = new IType[parameters.Count];
2314
for (int i = 0; i < parameterTypes.Length; i++) {
2315
parameterTypes[i] = SpecialType.UnknownType;
2317
return GetHypothesis(parameterTypes);
2319
// We have the choice, so pick the hypothesis with the least missing parameter types
2320
LambdaTypeHypothesis bestHypothesis = hypotheses[0];
2321
int bestHypothesisUnknownParameters = bestHypothesis.CountUnknownParameters();
2322
for (int i = 1; i < hypotheses.Count; i++) {
2323
int c = hypotheses[i].CountUnknownParameters();
2324
if (c < bestHypothesisUnknownParameters ||
2325
(c == bestHypothesisUnknownParameters && hypotheses[i].success && !bestHypothesis.success))
2327
bestHypothesis = hypotheses[i];
2328
bestHypothesisUnknownParameters = c;
2331
return bestHypothesis;
2335
internal override void EnforceMerge(ResolveVisitor parentVisitor)
2337
GetAnyHypothesis().MergeInto(parentVisitor, SpecialType.UnknownType);
2340
public override bool IsImplicitlyTyped {
2341
get { return true; }
2344
public override bool IsAnonymousMethod {
2345
get { return false; }
2348
public override bool HasParameterList {
2349
get { return true; }
2352
public override bool IsAsync {
2353
get { return lambda != null && lambda.IsAsync; }
2356
public override string ToString()
2358
return "[ImplicitlyTypedLambda " + this.LambdaExpression + "]";
2363
/// Every possible set of parameter types gets its own 'hypothetical world'.
2364
/// It uses a nested ResolveVisitor that has its own resolve cache, so that resolve results cannot leave the hypothetical world.
2366
/// Only after overload resolution is applied and the actual parameter types are known, the winning hypothesis will be merged
2367
/// with the parent ResolveVisitor.
2368
/// This is done when the AnonymousFunctionConversion is applied on the parent visitor.
2370
sealed class LambdaTypeHypothesis : IResolveVisitorNavigator
2372
readonly ImplicitlyTypedLambda lambda;
2373
readonly IParameter[] lambdaParameters;
2374
internal readonly IType[] parameterTypes;
2375
readonly ResolveVisitor visitor;
2376
readonly CSharpResolver storedContext;
2378
internal readonly IType inferredReturnType;
2379
IList<Expression> returnExpressions;
2380
IList<ResolveResult> returnValues;
2381
bool isValidAsVoidMethod;
2382
bool isEndpointUnreachable;
2383
internal bool success;
2385
public LambdaTypeHypothesis(ImplicitlyTypedLambda lambda, IType[] parameterTypes, ResolveVisitor visitor,
2386
ICollection<ParameterDeclaration> parameterDeclarations, CSharpResolver storedContext)
2388
Debug.Assert(parameterTypes.Length == lambda.Parameters.Count);
2390
this.lambda = lambda;
2391
this.parameterTypes = parameterTypes;
2392
this.visitor = visitor;
2393
this.storedContext = storedContext;
2394
visitor.SetNavigator(this);
2396
Log.WriteLine("Analyzing " + ToString() + "...");
2398
CSharpResolver oldResolver = visitor.resolver;
2399
visitor.resolver = visitor.resolver.WithIsWithinLambdaExpression(true);
2400
lambdaParameters = new IParameter[parameterTypes.Length];
2401
if (parameterDeclarations != null) {
2403
foreach (var pd in parameterDeclarations) {
2404
lambdaParameters[i] = new DefaultParameter(parameterTypes[i], pd.Name, visitor.MakeRegion(pd));
2405
visitor.resolver = visitor.resolver.AddVariable(lambdaParameters[i]);
2410
for (int i = 0; i < parameterTypes.Length; i++) {
2411
var p = lambda.Parameters[i];
2412
lambdaParameters[i] = new DefaultParameter(parameterTypes[i], p.Name, p.Region);
2413
visitor.resolver = visitor.resolver.AddVariable(lambdaParameters[i]);
2418
visitor.AnalyzeLambda(lambda.BodyExpression, lambda.IsAsync, out isValidAsVoidMethod, out isEndpointUnreachable, out inferredReturnType, out returnExpressions, out returnValues);
2419
visitor.resolver = oldResolver;
2421
Log.WriteLine("Finished analyzing " + ToString());
2424
ResolveVisitorNavigationMode IResolveVisitorNavigator.Scan(AstNode node)
2426
return ResolveVisitorNavigationMode.Resolve;
2429
void IResolveVisitorNavigator.Resolved(AstNode node, ResolveResult result)
2435
void IResolveVisitorNavigator.ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType)
2437
success &= conversion.IsValid;
2440
internal int CountUnknownParameters()
2443
foreach (IType t in parameterTypes) {
2444
if (t.Kind == TypeKind.Unknown)
2450
public Conversion IsValid(IType returnType, CSharpConversions conversions)
2452
bool valid = success && IsValidLambda(isValidAsVoidMethod, isEndpointUnreachable, lambda.IsAsync, returnValues, returnType, conversions);
2453
return new AnonymousFunctionConversion(returnType, this, valid);
2456
public void MergeInto(ResolveVisitor parentVisitor, IType returnType)
2458
if (returnType == null)
2459
throw new ArgumentNullException("returnType");
2460
if (parentVisitor != lambda.parentVisitor)
2461
throw new InvalidOperationException("parent visitor mismatch");
2463
if (lambda.winningHypothesis == this)
2465
else if (lambda.winningHypothesis != null)
2466
throw new InvalidOperationException("Trying to merge conflicting hypotheses");
2469
returnType = parentVisitor.UnpackTask(returnType);
2471
lambda.winningHypothesis = this;
2472
lambda.parameters = lambdaParameters; // replace untyped parameters with typed parameters
2473
if (lambda.BodyExpression is Expression && returnValues.Count == 1) {
2474
lambda.bodyResult = returnValues[0];
2475
if (!returnType.IsKnownType(KnownTypeCode.Void)) {
2476
var conv = storedContext.conversions.ImplicitConversion(lambda.bodyResult, returnType);
2477
if (!conv.IsIdentityConversion)
2478
lambda.bodyResult = new ConversionResolveResult(returnType, lambda.bodyResult, conv, storedContext.CheckForOverflow);
2482
Log.WriteLine("Applying return type {0} to implicitly-typed lambda {1}", returnType, lambda.LambdaExpression);
2483
if (returnType.Kind != TypeKind.Void) {
2484
for (int i = 0; i < returnExpressions.Count; i++) {
2485
visitor.ProcessConversion(returnExpressions[i], returnValues[i], returnType);
2489
visitor.MergeUndecidedLambdas();
2490
Log.WriteLine("Merging " + ToString());
2491
foreach (var pair in visitor.resolverBeforeDict) {
2492
Debug.Assert(!parentVisitor.resolverBeforeDict.ContainsKey(pair.Key));
2493
parentVisitor.resolverBeforeDict[pair.Key] = pair.Value;
2495
foreach (var pair in visitor.resolverAfterDict) {
2496
Debug.Assert(!parentVisitor.resolverAfterDict.ContainsKey(pair.Key));
2497
parentVisitor.resolverAfterDict[pair.Key] = pair.Value;
2499
foreach (var pair in visitor.resolveResultCache) {
2500
parentVisitor.StoreResult(pair.Key, pair.Value);
2502
parentVisitor.ImportConversions(visitor);
2503
parentVisitor.undecidedLambdas.Remove(lambda);
2506
public override string ToString()
2508
StringBuilder b = new StringBuilder();
2509
b.Append("[LambdaTypeHypothesis (");
2510
for (int i = 0; i < parameterTypes.Length; i++) {
2511
if (i > 0) b.Append(", ");
2512
b.Append(parameterTypes[i]);
2514
b.Append(lambda.Parameters[i].Name);
2517
b.Append(lambda.BodyExpression.ToString());
2519
return b.ToString();
2524
#region MergeUndecidedLambdas
2525
abstract class LambdaBase : LambdaResolveResult
2527
internal abstract bool IsUndecided { get; }
2528
internal abstract AstNode LambdaExpression { get; }
2529
internal abstract AstNode BodyExpression { get; }
2531
internal abstract void EnforceMerge(ResolveVisitor parentVisitor);
2533
public override ResolveResult ShallowClone()
2536
throw new NotSupportedException();
2537
return base.ShallowClone();
2541
void MergeUndecidedLambdas()
2543
if (undecidedLambdas == null || undecidedLambdas.Count == 0)
2545
Log.WriteLine("MergeUndecidedLambdas()...");
2547
while (undecidedLambdas.Count > 0) {
2548
LambdaBase lambda = undecidedLambdas[0];
2549
// may happen caused by parse error l =>
2550
if (lambda.LambdaExpression == null) {
2551
undecidedLambdas.Remove (lambda);
2554
ResolveParentForConversion(lambda.LambdaExpression);
2555
if (lambda.IsUndecided) {
2556
// Lambda wasn't merged by resolving its parent -> enforce merging
2557
Log.WriteLine("Lambda wasn't merged by conversion - enforce merging");
2558
lambda.EnforceMerge(this);
2562
Log.WriteLine("MergeUndecidedLambdas() finished.");
2565
void ResolveParentForConversion(AstNode expression)
2567
AstNode parent = expression.Parent;
2568
// Continue going upwards until we find a node that can be resolved and provides
2569
// an expected type.
2570
while (ParenthesizedExpression.ActsAsParenthesizedExpression(parent) || CSharpAstResolver.IsUnresolvableNode(parent)) {
2571
parent = parent.Parent;
2573
CSharpResolver storedResolver;
2574
if (parent != null && resolverBeforeDict.TryGetValue(parent, out storedResolver)) {
2575
Log.WriteLine("Trying to resolve '" + parent + "' in order to find the conversion applied to '" + expression + "'...");
2577
ResetContext(storedResolver, delegate { Resolve(parent); });
2580
Log.WriteLine("Could not find a suitable parent for '" + expression + "'");
2585
#region AnalyzeLambda
2586
IType GetTaskType(IType resultType)
2588
if (resultType.Kind == TypeKind.Unknown)
2589
return SpecialType.UnknownType;
2590
if (resultType.Kind == TypeKind.Void)
2591
return resolver.Compilation.FindType(KnownTypeCode.Task);
2593
ITypeDefinition def = resolver.Compilation.FindType(KnownTypeCode.TaskOfT).GetDefinition();
2595
return new ParameterizedType(def, new[] { resultType });
2597
return SpecialType.UnknownType;
2600
void AnalyzeLambda(AstNode body, bool isAsync, out bool isValidAsVoidMethod, out bool isEndpointUnreachable, out IType inferredReturnType, out IList<Expression> returnExpressions, out IList<ResolveResult> returnValues)
2602
isEndpointUnreachable = false;
2603
Expression expr = body as Expression;
2605
isValidAsVoidMethod = ExpressionPermittedAsStatement(expr);
2606
returnExpressions = new [] { expr };
2607
returnValues = new[] { Resolve(expr) };
2608
inferredReturnType = returnValues[0].Type;
2612
AnalyzeLambdaVisitor alv = new AnalyzeLambdaVisitor();
2613
body.AcceptVisitor(alv);
2614
isValidAsVoidMethod = (alv.ReturnExpressions.Count == 0);
2615
if (alv.HasVoidReturnStatements) {
2616
returnExpressions = EmptyList<Expression>.Instance;
2617
returnValues = EmptyList<ResolveResult>.Instance;
2618
inferredReturnType = resolver.Compilation.FindType(KnownTypeCode.Void);
2620
returnExpressions = alv.ReturnExpressions;
2621
returnValues = new ResolveResult[returnExpressions.Count];
2622
for (int i = 0; i < returnValues.Count; i++) {
2623
returnValues[i] = resolveResultCache[returnExpressions[i]];
2626
// async lambdas without return statements are resolved as Task return types.
2627
if (returnExpressions.Count == 0 && isAsync) {
2628
inferredReturnType = resolver.Compilation.FindType(KnownTypeCode.Task);
2629
Log.WriteLine("Lambda return type was inferred to: " + inferredReturnType);
2633
TypeInference ti = new TypeInference(resolver.Compilation, resolver.conversions);
2635
inferredReturnType = ti.GetBestCommonType(returnValues, out tiSuccess);
2636
// Failure to infer a return type does not make the lambda invalid,
2637
// so we can ignore the 'tiSuccess' value
2638
if (isValidAsVoidMethod && returnExpressions.Count == 0 && body is Statement) {
2639
var reachabilityAnalysis = ReachabilityAnalysis.Create(
2640
(Statement)body, (node, _) => resolveResultCache[node],
2641
resolver.CurrentTypeResolveContext, cancellationToken);
2642
isEndpointUnreachable = !reachabilityAnalysis.IsEndpointReachable((Statement)body);
2647
inferredReturnType = GetTaskType(inferredReturnType);
2648
Log.WriteLine("Lambda return type was inferred to: " + inferredReturnType);
2651
static bool ExpressionPermittedAsStatement(Expression expr)
2653
UnaryOperatorExpression uoe = expr as UnaryOperatorExpression;
2655
switch (uoe.Operator) {
2656
case UnaryOperatorType.Increment:
2657
case UnaryOperatorType.Decrement:
2658
case UnaryOperatorType.PostIncrement:
2659
case UnaryOperatorType.PostDecrement:
2660
case UnaryOperatorType.Await:
2666
return expr is InvocationExpression
2667
|| expr is ObjectCreateExpression
2668
|| expr is AssignmentExpression;
2671
static bool IsValidLambda(bool isValidAsVoidMethod, bool isEndpointUnreachable, bool isAsync, IList<ResolveResult> returnValues, IType returnType, CSharpConversions conversions)
2673
if (returnType.Kind == TypeKind.Void) {
2674
// Lambdas that are valid statement lambdas or expression lambdas with a statement-expression
2675
// can be converted to delegates with void return type.
2676
// This holds for both async and regular lambdas.
2677
return isValidAsVoidMethod;
2678
} else if (isAsync && IsTask(returnType) && returnType.TypeParameterCount == 0) {
2679
// Additionally, async lambdas with the above property can be converted to non-generic Task.
2680
return isValidAsVoidMethod;
2682
if (returnValues.Count == 0)
2683
return isEndpointUnreachable;
2685
// async lambdas must return Task<T>
2686
if (!(IsTask(returnType) && returnType.TypeParameterCount == 1))
2688
// unpack Task<T> for testing the implicit conversions
2689
returnType = ((ParameterizedType)returnType).GetTypeArgument(0);
2691
foreach (ResolveResult returnRR in returnValues) {
2692
if (!conversions.ImplicitConversion(returnRR, returnType).IsValid)
2700
/// Gets the T in Task<T>.
2701
/// Returns void for non-generic Task.
2702
/// Any other type is returned unmodified.
2704
IType UnpackTask(IType type)
2708
if (type.TypeParameterCount == 0)
2709
return resolver.Compilation.FindType(KnownTypeCode.Void);
2711
return ((ParameterizedType)type).GetTypeArgument(0);
2715
/// Gets whether the specified type is Task or Task<T>.
2717
static bool IsTask(IType type)
2719
ITypeDefinition def = type.GetDefinition();
2721
if (def.KnownTypeCode == KnownTypeCode.Task)
2723
if (def.KnownTypeCode == KnownTypeCode.TaskOfT)
2724
return type is ParameterizedType;
2729
sealed class AnalyzeLambdaVisitor : DepthFirstAstVisitor
2731
public bool HasVoidReturnStatements;
2732
public List<Expression> ReturnExpressions = new List<Expression>();
2734
public override void VisitReturnStatement(ReturnStatement returnStatement)
2736
Expression expr = returnStatement.Expression;
2738
HasVoidReturnStatements = true;
2740
ReturnExpressions.Add(expr);
2744
public override void VisitAnonymousMethodExpression(AnonymousMethodExpression anonymousMethodExpression)
2746
// don't go into nested lambdas
2749
public override void VisitLambdaExpression(LambdaExpression lambdaExpression)
2751
// don't go into nested lambdas
2757
#region ForEach Statement
2758
ResolveResult IAstVisitor<ResolveResult>.VisitForeachStatement(ForeachStatement foreachStatement)
2760
var compilation = resolver.Compilation;
2761
ResolveResult expression = Resolve(foreachStatement.InExpression);
2762
bool isImplicitlyTypedVariable = IsVar(foreachStatement.VariableType);
2763
var memberLookup = resolver.CreateMemberLookup();
2765
IType collectionType, enumeratorType, elementType;
2766
ResolveResult getEnumeratorInvocation;
2767
ResolveResult currentRR = null;
2768
// C# 4.0 spec: Ā§8.8.4 The foreach statement
2769
if (expression.Type.Kind == TypeKind.Array || expression.Type.Kind == TypeKind.Dynamic) {
2770
collectionType = compilation.FindType(KnownTypeCode.IEnumerable);
2771
enumeratorType = compilation.FindType(KnownTypeCode.IEnumerator);
2772
if (expression.Type.Kind == TypeKind.Array) {
2773
elementType = ((ArrayType)expression.Type).ElementType;
2775
elementType = isImplicitlyTypedVariable ? SpecialType.Dynamic : compilation.FindType(KnownTypeCode.Object);
2777
getEnumeratorInvocation = resolver.ResolveCast(collectionType, expression);
2778
getEnumeratorInvocation = resolver.ResolveMemberAccess(getEnumeratorInvocation, "GetEnumerator", EmptyList<IType>.Instance, NameLookupMode.InvocationTarget);
2779
getEnumeratorInvocation = resolver.ResolveInvocation(getEnumeratorInvocation, new ResolveResult[0]);
2781
var getEnumeratorMethodGroup = memberLookup.Lookup(expression, "GetEnumerator", EmptyList<IType>.Instance, true) as MethodGroupResolveResult;
2782
if (getEnumeratorMethodGroup != null) {
2783
var or = getEnumeratorMethodGroup.PerformOverloadResolution(
2784
compilation, new ResolveResult[0],
2785
allowExtensionMethods: false, allowExpandingParams: false, allowOptionalParameters: false);
2786
if (or.FoundApplicableCandidate && !or.IsAmbiguous && !or.BestCandidate.IsStatic && or.BestCandidate.IsPublic) {
2787
collectionType = expression.Type;
2788
getEnumeratorInvocation = or.CreateResolveResult(expression);
2789
enumeratorType = getEnumeratorInvocation.Type;
2790
currentRR = memberLookup.Lookup(new ResolveResult(enumeratorType), "Current", EmptyList<IType>.Instance, false);
2791
elementType = currentRR.Type;
2793
CheckForEnumerableInterface(expression, out collectionType, out enumeratorType, out elementType, out getEnumeratorInvocation);
2796
CheckForEnumerableInterface(expression, out collectionType, out enumeratorType, out elementType, out getEnumeratorInvocation);
2799
IMethod moveNextMethod = null;
2800
var moveNextMethodGroup = memberLookup.Lookup(new ResolveResult(enumeratorType), "MoveNext", EmptyList<IType>.Instance, false) as MethodGroupResolveResult;
2801
if (moveNextMethodGroup != null) {
2802
var or = moveNextMethodGroup.PerformOverloadResolution(
2803
compilation, new ResolveResult[0],
2804
allowExtensionMethods: false, allowExpandingParams: false, allowOptionalParameters: false);
2805
moveNextMethod = or.GetBestCandidateWithSubstitutedTypeArguments() as IMethod;
2808
if (currentRR == null)
2809
currentRR = memberLookup.Lookup(new ResolveResult(enumeratorType), "Current", EmptyList<IType>.Instance, false);
2810
IProperty currentProperty = null;
2811
if (currentRR is MemberResolveResult)
2812
currentProperty = ((MemberResolveResult)currentRR).Member as IProperty;
2813
// end of foreach resolve logic
2814
// back to resolve visitor:
2816
resolver = resolver.PushBlock();
2818
if (isImplicitlyTypedVariable) {
2819
StoreCurrentState(foreachStatement.VariableType);
2820
StoreResult(foreachStatement.VariableType, new TypeResolveResult(elementType));
2821
v = MakeVariable(elementType, foreachStatement.VariableNameToken);
2823
IType variableType = ResolveType(foreachStatement.VariableType);
2824
v = MakeVariable(variableType, foreachStatement.VariableNameToken);
2826
StoreCurrentState(foreachStatement.VariableNameToken);
2827
resolver = resolver.AddVariable(v);
2829
StoreResult(foreachStatement.VariableNameToken, new LocalResolveResult(v));
2831
Scan(foreachStatement.EmbeddedStatement);
2832
resolver = resolver.PopBlock();
2833
return new ForEachResolveResult(getEnumeratorInvocation, collectionType, enumeratorType, elementType,
2834
v, currentProperty, moveNextMethod, voidResult.Type);
2837
void CheckForEnumerableInterface(ResolveResult expression, out IType collectionType, out IType enumeratorType, out IType elementType, out ResolveResult getEnumeratorInvocation)
2839
var compilation = resolver.Compilation;
2841
elementType = GetElementTypeFromIEnumerable(expression.Type, compilation, false, out isGeneric);
2842
if (isGeneric == true) {
2843
ITypeDefinition enumerableOfT = compilation.FindType(KnownTypeCode.IEnumerableOfT).GetDefinition();
2844
if (enumerableOfT != null)
2845
collectionType = new ParameterizedType(enumerableOfT, new [] { elementType });
2847
collectionType = SpecialType.UnknownType;
2849
ITypeDefinition enumeratorOfT = compilation.FindType(KnownTypeCode.IEnumeratorOfT).GetDefinition();
2850
if (enumeratorOfT != null)
2851
enumeratorType = new ParameterizedType(enumeratorOfT, new [] { elementType });
2853
enumeratorType = SpecialType.UnknownType;
2854
} else if (isGeneric == false) {
2855
collectionType = compilation.FindType(KnownTypeCode.IEnumerable);
2856
enumeratorType = compilation.FindType(KnownTypeCode.IEnumerator);
2858
collectionType = SpecialType.UnknownType;
2859
enumeratorType = SpecialType.UnknownType;
2861
getEnumeratorInvocation = resolver.ResolveCast(collectionType, expression);
2862
getEnumeratorInvocation = resolver.ResolveMemberAccess(getEnumeratorInvocation, "GetEnumerator", EmptyList<IType>.Instance, NameLookupMode.InvocationTarget);
2863
getEnumeratorInvocation = resolver.ResolveInvocation(getEnumeratorInvocation, new ResolveResult[0]);
2867
#region Local Variable Scopes (Block Statements)
2868
ResolveResult IAstVisitor<ResolveResult>.VisitBlockStatement(BlockStatement blockStatement)
2870
resolver = resolver.PushBlock();
2871
ScanChildren(blockStatement);
2872
resolver = resolver.PopBlock();
2876
ResolveResult IAstVisitor<ResolveResult>.VisitUsingStatement(UsingStatement usingStatement)
2878
resolver = resolver.PushBlock();
2879
if (resolverEnabled) {
2880
for (AstNode child = usingStatement.FirstChild; child != null; child = child.NextSibling) {
2881
if (child.Role == UsingStatement.ResourceAcquisitionRole && child is Expression) {
2882
ResolveAndProcessConversion((Expression)child, resolver.Compilation.FindType(KnownTypeCode.IDisposable));
2888
ScanChildren(usingStatement);
2890
resolver = resolver.PopBlock();
2891
return resolverEnabled ? voidResult : null;
2894
ResolveResult IAstVisitor<ResolveResult>.VisitFixedStatement(FixedStatement fixedStatement)
2896
resolver = resolver.PushBlock();
2897
IType type = ResolveType(fixedStatement.Type);
2898
foreach (VariableInitializer vi in fixedStatement.Variables) {
2899
resolver = resolver.AddVariable(MakeVariable(type, vi.NameToken));
2902
Scan(fixedStatement.EmbeddedStatement);
2903
resolver = resolver.PopBlock();
2907
ResolveResult IAstVisitor<ResolveResult>.VisitSwitchStatement(SwitchStatement switchStatement)
2909
resolver = resolver.PushBlock();
2910
ScanChildren(switchStatement);
2911
resolver = resolver.PopBlock();
2915
ResolveResult IAstVisitor<ResolveResult>.VisitCatchClause(CatchClause catchClause)
2917
resolver = resolver.PushBlock();
2918
if (string.IsNullOrEmpty(catchClause.VariableName)) {
2919
Scan(catchClause.Type);
2921
//DomRegion region = MakeRegion(catchClause.VariableNameToken);
2922
StoreCurrentState(catchClause.VariableNameToken);
2923
IVariable v = MakeVariable(ResolveType(catchClause.Type), catchClause.VariableNameToken);
2924
resolver = resolver.AddVariable(v);
2925
StoreResult(catchClause.VariableNameToken, new LocalResolveResult(v));
2927
Scan(catchClause.Body);
2928
resolver = resolver.PopBlock();
2933
#region VariableDeclarationStatement
2934
ResolveResult IAstVisitor<ResolveResult>.VisitVariableDeclarationStatement(VariableDeclarationStatement variableDeclarationStatement)
2936
bool isConst = (variableDeclarationStatement.Modifiers & Modifiers.Const) != 0;
2937
if (!isConst && IsVar(variableDeclarationStatement.Type) && variableDeclarationStatement.Variables.Count == 1) {
2938
VariableInitializer vi = variableDeclarationStatement.Variables.Single();
2939
StoreCurrentState(variableDeclarationStatement.Type);
2940
IType type = Resolve(vi.Initializer).Type;
2941
StoreResult(variableDeclarationStatement.Type, new TypeResolveResult(type));
2942
IVariable v = MakeVariable(type, vi.NameToken);
2943
resolver = resolver.AddVariable(v);
2946
IType type = ResolveType(variableDeclarationStatement.Type);
2948
foreach (VariableInitializer vi in variableDeclarationStatement.Variables) {
2951
ResolveResult rr = Resolve(vi.Initializer);
2952
rr = resolver.ResolveCast(type, rr);
2953
v = MakeConstant(type, vi.NameToken, rr.ConstantValue);
2955
v = MakeVariable(type, vi.NameToken);
2957
resolver = resolver.AddVariable(v);
2965
#region Condition Statements
2966
ResolveResult IAstVisitor<ResolveResult>.VisitForStatement(ForStatement forStatement)
2968
resolver = resolver.PushBlock();
2969
var result = HandleConditionStatement(forStatement);
2970
resolver = resolver.PopBlock();
2974
ResolveResult IAstVisitor<ResolveResult>.VisitIfElseStatement(IfElseStatement ifElseStatement)
2976
return HandleConditionStatement(ifElseStatement);
2979
ResolveResult IAstVisitor<ResolveResult>.VisitWhileStatement(WhileStatement whileStatement)
2981
return HandleConditionStatement(whileStatement);
2984
ResolveResult IAstVisitor<ResolveResult>.VisitDoWhileStatement(DoWhileStatement doWhileStatement)
2986
return HandleConditionStatement(doWhileStatement);
2989
ResolveResult HandleConditionStatement(Statement conditionStatement)
2991
if (resolverEnabled) {
2992
for (AstNode child = conditionStatement.FirstChild; child != null; child = child.NextSibling) {
2993
if (child.Role == Roles.Condition) {
2994
Expression condition = (Expression)child;
2995
ResolveResult conditionRR = Resolve(condition);
2996
ResolveResult convertedRR = resolver.ResolveCondition(conditionRR);
2997
if (convertedRR != conditionRR)
2998
ProcessConversionResult(condition, convertedRR as ConversionResolveResult);
3005
ScanChildren(conditionStatement);
3011
#region Return Statements
3012
ResolveResult IAstVisitor<ResolveResult>.VisitReturnStatement(ReturnStatement returnStatement)
3014
if (resolverEnabled && !resolver.IsWithinLambdaExpression && resolver.CurrentMember != null) {
3015
IType type = resolver.CurrentMember.ReturnType;
3017
var methodDecl = returnStatement.Ancestors.OfType<EntityDeclaration>().FirstOrDefault();
3018
if (methodDecl != null && (methodDecl.Modifiers & Modifiers.Async) == Modifiers.Async)
3019
type = UnpackTask(type);
3021
ResolveAndProcessConversion(returnStatement.Expression, type);
3023
Scan(returnStatement.Expression);
3025
return resolverEnabled ? voidResult : null;
3028
ResolveResult IAstVisitor<ResolveResult>.VisitYieldReturnStatement(YieldReturnStatement yieldStatement)
3030
if (resolverEnabled && resolver.CurrentMember != null) {
3031
IType returnType = resolver.CurrentMember.ReturnType;
3033
IType elementType = GetElementTypeFromIEnumerable(returnType, resolver.Compilation, true, out isGeneric);
3034
ResolveAndProcessConversion(yieldStatement.Expression, elementType);
3036
Scan(yieldStatement.Expression);
3038
return resolverEnabled ? voidResult : null;
3041
ResolveResult IAstVisitor<ResolveResult>.VisitYieldBreakStatement(YieldBreakStatement yieldBreakStatement)
3047
#region Other statements
3048
ResolveResult IAstVisitor<ResolveResult>.VisitExpressionStatement(ExpressionStatement expressionStatement)
3050
ScanChildren(expressionStatement);
3054
ResolveResult IAstVisitor<ResolveResult>.VisitLockStatement(LockStatement lockStatement)
3056
ScanChildren(lockStatement);
3060
ResolveResult IAstVisitor<ResolveResult>.VisitEmptyStatement(EmptyStatement emptyStatement)
3065
ResolveResult IAstVisitor<ResolveResult>.VisitBreakStatement(BreakStatement breakStatement)
3070
ResolveResult IAstVisitor<ResolveResult>.VisitContinueStatement(ContinueStatement continueStatement)
3075
ResolveResult IAstVisitor<ResolveResult>.VisitThrowStatement(ThrowStatement throwStatement)
3077
if (resolverEnabled) {
3078
ResolveAndProcessConversion(throwStatement.Expression, resolver.Compilation.FindType(KnownTypeCode.Exception));
3081
Scan(throwStatement.Expression);
3086
ResolveResult IAstVisitor<ResolveResult>.VisitTryCatchStatement(TryCatchStatement tryCatchStatement)
3088
ScanChildren(tryCatchStatement);
3092
ResolveResult IAstVisitor<ResolveResult>.VisitGotoCaseStatement(GotoCaseStatement gotoCaseStatement)
3094
ScanChildren(gotoCaseStatement);
3098
ResolveResult IAstVisitor<ResolveResult>.VisitGotoDefaultStatement(GotoDefaultStatement gotoDefaultStatement)
3103
ResolveResult IAstVisitor<ResolveResult>.VisitGotoStatement(GotoStatement gotoStatement)
3108
ResolveResult IAstVisitor<ResolveResult>.VisitLabelStatement(LabelStatement labelStatement)
3113
ResolveResult IAstVisitor<ResolveResult>.VisitUnsafeStatement(UnsafeStatement unsafeStatement)
3115
resolver = resolver.PushBlock();
3116
ScanChildren(unsafeStatement);
3117
resolver = resolver.PopBlock();
3122
#region Local Variable Type Inference
3123
static bool IsVar(AstNode returnType)
3125
SimpleType st = returnType as SimpleType;
3126
return st != null && st.Identifier == "var" && st.TypeArguments.Count == 0;
3129
IVariable MakeVariable(IType type, Identifier variableName)
3131
return new SimpleVariable(MakeRegion(variableName), type, variableName.Name);
3134
IVariable MakeConstant(IType type, Identifier variableName, object constantValue)
3136
return new SimpleConstant(MakeRegion(variableName), type, variableName.Name, constantValue);
3139
class SimpleVariable : IVariable
3141
readonly DomRegion region;
3142
readonly IType type;
3143
readonly string name;
3145
public SimpleVariable(DomRegion region, IType type, string name)
3147
Debug.Assert(type != null);
3148
Debug.Assert(name != null);
3149
this.region = region;
3154
public string Name {
3155
get { return name; }
3158
public DomRegion Region {
3159
get { return region; }
3163
get { return type; }
3166
public virtual bool IsConst {
3167
get { return false; }
3170
public virtual object ConstantValue {
3171
get { return null; }
3174
public override string ToString()
3176
return type.ToString() + " " + name + ";";
3180
sealed class SimpleConstant : SimpleVariable
3182
readonly object constantValue;
3184
public SimpleConstant(DomRegion region, IType type, string name, object constantValue)
3185
: base(region, type, name)
3187
this.constantValue = constantValue;
3190
public override bool IsConst {
3191
get { return true; }
3194
public override object ConstantValue {
3195
get { return constantValue; }
3198
public override string ToString()
3200
return Type.ToString() + " " + Name + " = " + new PrimitiveExpression(constantValue).ToString() + ";";
3204
static IType GetElementTypeFromIEnumerable(IType collectionType, ICompilation compilation, bool allowIEnumerator, out bool? isGeneric)
3206
bool foundNonGenericIEnumerable = false;
3207
foreach (IType baseType in collectionType.GetAllBaseTypes()) {
3208
ITypeDefinition baseTypeDef = baseType.GetDefinition();
3209
if (baseTypeDef != null) {
3210
KnownTypeCode typeCode = baseTypeDef.KnownTypeCode;
3211
if (typeCode == KnownTypeCode.IEnumerableOfT || (allowIEnumerator && typeCode == KnownTypeCode.IEnumeratorOfT)) {
3212
ParameterizedType pt = baseType as ParameterizedType;
3215
return pt.GetTypeArgument(0);
3218
if (typeCode == KnownTypeCode.IEnumerable || (allowIEnumerator && typeCode == KnownTypeCode.IEnumerator))
3219
foundNonGenericIEnumerable = true;
3222
// System.Collections.IEnumerable found in type hierarchy -> Object is element type.
3223
if (foundNonGenericIEnumerable) {
3225
return compilation.FindType(KnownTypeCode.Object);
3228
return SpecialType.UnknownType;
3233
ResolveResult IAstVisitor<ResolveResult>.VisitAttribute(Attribute attribute)
3235
var type = ResolveType(attribute.Type);
3237
// Separate arguments into ctor arguments and non-ctor arguments:
3238
var constructorArguments = attribute.Arguments.Where(a => !(a is NamedExpression));
3239
var nonConstructorArguments = attribute.Arguments.OfType<NamedExpression>();
3241
// Scan the non-constructor arguments
3242
resolver = resolver.PushObjectInitializer(new InitializedObjectResolveResult(type));
3243
List<ResolveResult> initializerStatements = new List<ResolveResult>();
3244
foreach (var arg in nonConstructorArguments)
3245
HandleNamedExpression(arg, initializerStatements);
3246
resolver = resolver.PopObjectInitializer();
3248
// Resolve the ctor arguments and find the matching ctor overload
3249
string[] argumentNames;
3250
ResolveResult[] arguments = GetArguments(constructorArguments, out argumentNames);
3251
ResolveResult rr = resolver.ResolveObjectCreation(type, arguments, argumentNames, false, initializerStatements);
3252
ProcessInvocationResult(null, constructorArguments, rr);
3256
ResolveResult IAstVisitor<ResolveResult>.VisitAttributeSection(AttributeSection attributeSection)
3258
ScanChildren(attributeSection);
3263
#region Using Declaration
3264
ResolveResult IAstVisitor<ResolveResult>.VisitUsingDeclaration(UsingDeclaration usingDeclaration)
3266
ScanChildren(usingDeclaration);
3270
ResolveResult IAstVisitor<ResolveResult>.VisitUsingAliasDeclaration(UsingAliasDeclaration usingDeclaration)
3272
ScanChildren(usingDeclaration);
3276
ResolveResult IAstVisitor<ResolveResult>.VisitExternAliasDeclaration(ExternAliasDeclaration externAliasDeclaration)
3282
#region Type References
3283
ResolveResult IAstVisitor<ResolveResult>.VisitPrimitiveType(PrimitiveType primitiveType)
3285
if (!resolverEnabled)
3287
KnownTypeCode typeCode = primitiveType.KnownTypeCode;
3288
if (typeCode == KnownTypeCode.None && primitiveType.Parent is Constraint && primitiveType.Role == Roles.BaseType) {
3289
switch (primitiveType.Keyword) {
3296
IType type = resolver.Compilation.FindType(typeCode);
3297
return new TypeResolveResult(type);
3300
ResolveResult IAstVisitor<ResolveResult>.VisitSimpleType(SimpleType simpleType)
3302
if (!resolverEnabled) {
3303
ScanChildren(simpleType);
3307
// Figure out the correct lookup mode:
3308
NameLookupMode lookupMode = simpleType.GetNameLookupMode();
3310
var typeArguments = ResolveTypeArguments(simpleType.TypeArguments);
3311
Identifier identifier = simpleType.IdentifierToken;
3312
if (string.IsNullOrEmpty(identifier.Name))
3313
return new TypeResolveResult(SpecialType.UnboundTypeArgument);
3314
ResolveResult rr = resolver.LookupSimpleNameOrTypeName(identifier.Name, typeArguments, lookupMode);
3315
if (simpleType.Parent is Attribute && !identifier.IsVerbatim) {
3316
var withSuffix = resolver.LookupSimpleNameOrTypeName(identifier.Name + "Attribute", typeArguments, lookupMode);
3317
if (AttributeTypeReference.PreferAttributeTypeWithSuffix(rr.Type, withSuffix.Type, resolver.Compilation))
3323
ResolveResult IAstVisitor<ResolveResult>.VisitMemberType(MemberType memberType)
3325
ResolveResult target;
3326
if (memberType.IsDoubleColon && memberType.Target is SimpleType) {
3327
SimpleType t = (SimpleType)memberType.Target;
3328
StoreCurrentState(t);
3329
target = resolver.ResolveAlias(t.Identifier);
3330
StoreResult(t, target);
3332
if (!resolverEnabled) {
3333
ScanChildren(memberType);
3336
target = Resolve(memberType.Target);
3339
NameLookupMode lookupMode = memberType.GetNameLookupMode();
3340
var typeArguments = ResolveTypeArguments(memberType.TypeArguments);
3341
Identifier identifier = memberType.MemberNameToken;
3342
ResolveResult rr = resolver.ResolveMemberAccess(target, identifier.Name, typeArguments, lookupMode);
3343
if (memberType.Parent is Attribute && !identifier.IsVerbatim) {
3344
var withSuffix = resolver.ResolveMemberAccess(target, identifier.Name + "Attribute", typeArguments, lookupMode);
3345
if (AttributeTypeReference.PreferAttributeTypeWithSuffix(rr.Type, withSuffix.Type, resolver.Compilation))
3351
ResolveResult IAstVisitor<ResolveResult>.VisitComposedType(ComposedType composedType)
3353
if (!resolverEnabled) {
3354
ScanChildren(composedType);
3357
IType t = ResolveType(composedType.BaseType);
3358
if (composedType.HasNullableSpecifier) {
3359
t = NullableType.Create(resolver.Compilation, t);
3361
for (int i = 0; i < composedType.PointerRank; i++) {
3362
t = new PointerType(t);
3364
foreach (var a in composedType.ArraySpecifiers.Reverse()) {
3365
t = new ArrayType(resolver.Compilation, t, a.Dimensions);
3367
return new TypeResolveResult(t);
3371
#region Query Expressions
3372
ResolveResult IAstVisitor<ResolveResult>.VisitQueryExpression(QueryExpression queryExpression)
3374
resolver = resolver.PushBlock();
3375
var oldQueryResult = currentQueryResult;
3376
var oldCancellationToken = cancellationToken;
3378
// Because currentQueryResult isn't part of the stored state,
3379
// query expressions must be resolved in a single operation.
3380
// This means we can't allow cancellation within the query expression.
3381
cancellationToken = CancellationToken.None;
3382
currentQueryResult = null;
3383
foreach (var clause in queryExpression.Clauses) {
3384
currentQueryResult = Resolve(clause);
3386
return WrapResult(currentQueryResult);
3388
currentQueryResult = oldQueryResult;
3389
cancellationToken = oldCancellationToken;
3390
resolver = resolver.PopBlock();
3394
IType GetTypeForQueryVariable(IType type)
3396
// This assumes queries are only used on IEnumerable.
3397
// We might want to look at the signature of a LINQ method (e.g. Select) instead.
3399
return GetElementTypeFromIEnumerable(type, resolver.Compilation, false, out isGeneric);
3402
ResolveResult MakeTransparentIdentifierResolveResult()
3404
return new ResolveResult(new AnonymousType(resolver.Compilation, EmptyList<IUnresolvedProperty>.Instance));
3407
sealed class QueryExpressionLambdaConversion : Conversion
3409
internal readonly IType[] ParameterTypes;
3411
public QueryExpressionLambdaConversion(IType[] parameterTypes)
3413
this.ParameterTypes = parameterTypes;
3416
public override bool IsImplicit {
3417
get { return true; }
3420
public override bool IsAnonymousFunctionConversion {
3421
get { return true; }
3425
sealed class QueryExpressionLambda : LambdaResolveResult
3427
readonly IParameter[] parameters;
3428
readonly ResolveResult bodyExpression;
3430
internal IType[] inferredParameterTypes;
3432
public QueryExpressionLambda(int parameterCount, ResolveResult bodyExpression)
3434
this.parameters = new IParameter[parameterCount];
3435
for (int i = 0; i < parameterCount; i++) {
3436
parameters[i] = new DefaultParameter(SpecialType.UnknownType, "x" + i);
3438
this.bodyExpression = bodyExpression;
3441
public override IList<IParameter> Parameters {
3442
get { return parameters; }
3445
public override Conversion IsValid(IType[] parameterTypes, IType returnType, CSharpConversions conversions)
3447
if (parameterTypes.Length == parameters.Length) {
3448
this.inferredParameterTypes = parameterTypes;
3449
return new QueryExpressionLambdaConversion(parameterTypes);
3451
return Conversion.None;
3455
public override bool IsAsync {
3456
get { return false; }
3459
public override bool IsImplicitlyTyped {
3460
get { return true; }
3463
public override bool IsAnonymousMethod {
3464
get { return false; }
3467
public override bool HasParameterList {
3468
get { return true; }
3471
public override ResolveResult Body {
3472
get { return bodyExpression; }
3475
public override IType GetInferredReturnType(IType[] parameterTypes)
3477
return bodyExpression.Type;
3480
public override string ToString()
3482
return string.Format("[QueryExpressionLambda ({0}) => {1}]", string.Join(",", parameters.Select(p => p.Name)), bodyExpression);
3486
QueryClause GetPreviousQueryClause(QueryClause clause)
3488
for (AstNode node = clause.PrevSibling; node != null; node = node.PrevSibling) {
3489
if (node.Role == QueryExpression.ClauseRole)
3490
return (QueryClause)node;
3495
QueryClause GetNextQueryClause(QueryClause clause)
3497
for (AstNode node = clause.NextSibling; node != null; node = node.NextSibling) {
3498
if (node.Role == QueryExpression.ClauseRole)
3499
return (QueryClause)node;
3504
ResolveResult IAstVisitor<ResolveResult>.VisitQueryFromClause(QueryFromClause queryFromClause)
3506
ResolveResult result = errorResult;
3507
ResolveResult expr = Resolve(queryFromClause.Expression);
3509
if (queryFromClause.Type.IsNull) {
3510
v = MakeVariable(GetTypeForQueryVariable(expr.Type), queryFromClause.IdentifierToken);
3513
v = MakeVariable(ResolveType(queryFromClause.Type), queryFromClause.IdentifierToken);
3515
// resolve the .Cast<>() call
3516
ResolveResult methodGroup = resolver.ResolveMemberAccess(expr, "Cast", new[] { v.Type }, NameLookupMode.InvocationTarget);
3517
result = resolver.ResolveInvocation(methodGroup, new ResolveResult[0]);
3520
StoreCurrentState(queryFromClause.IdentifierToken);
3521
resolver = resolver.AddVariable(v);
3522
StoreResult(queryFromClause.IdentifierToken, new LocalResolveResult(v));
3524
if (currentQueryResult != null) {
3525
// this is a second 'from': resolve the .SelectMany() call
3526
QuerySelectClause selectClause = GetNextQueryClause(queryFromClause) as QuerySelectClause;
3527
ResolveResult selectResult;
3528
if (selectClause != null) {
3529
// from ... from ... select - the SelectMany call also performs the Select operation
3530
selectResult = Resolve(selectClause.Expression);
3532
// from .. from ... ... - introduce a transparent identifier
3533
selectResult = MakeTransparentIdentifierResolveResult();
3535
ResolveResult methodGroup = resolver.ResolveMemberAccess(currentQueryResult, "SelectMany", EmptyList<IType>.Instance, NameLookupMode.InvocationTarget);
3536
ResolveResult[] arguments = {
3537
new QueryExpressionLambda(1, result),
3538
new QueryExpressionLambda(2, selectResult)
3540
result = resolver.ResolveInvocation(methodGroup, arguments);
3543
return WrapResult(result);
3549
/// Wraps the result in an identity conversion.
3550
/// This is necessary so that '$from x in variable$ select x*2' does not resolve
3551
/// to the LocalResolveResult for the variable, which would confuse find references.
3553
ResolveResult WrapResult(ResolveResult result)
3555
return new ConversionResolveResult(result.Type, result, Conversion.IdentityConversion, resolver.CheckForOverflow);
3558
ResolveResult IAstVisitor<ResolveResult>.VisitQueryContinuationClause(QueryContinuationClause queryContinuationClause)
3560
ResolveResult rr = Resolve(queryContinuationClause.PrecedingQuery);
3561
IType variableType = GetTypeForQueryVariable(rr.Type);
3562
StoreCurrentState(queryContinuationClause.IdentifierToken);
3563
IVariable v = MakeVariable(variableType, queryContinuationClause.IdentifierToken);
3564
resolver = resolver.AddVariable(v);
3565
StoreResult(queryContinuationClause.IdentifierToken, new LocalResolveResult(v));
3566
return WrapResult(rr);
3569
ResolveResult IAstVisitor<ResolveResult>.VisitQueryLetClause(QueryLetClause queryLetClause)
3571
ResolveResult expr = Resolve(queryLetClause.Expression);
3572
StoreCurrentState(queryLetClause.IdentifierToken);
3573
IVariable v = MakeVariable(expr.Type, queryLetClause.IdentifierToken);
3574
resolver = resolver.AddVariable(v);
3575
StoreResult(queryLetClause.IdentifierToken, new LocalResolveResult(v));
3576
if (currentQueryResult != null) {
3577
// resolve the .Select() call
3578
ResolveResult methodGroup = resolver.ResolveMemberAccess(currentQueryResult, "Select", EmptyList<IType>.Instance, NameLookupMode.InvocationTarget);
3579
ResolveResult[] arguments = { new QueryExpressionLambda(1, MakeTransparentIdentifierResolveResult()) };
3580
return resolver.ResolveInvocation(methodGroup, arguments);
3586
ResolveResult IAstVisitor<ResolveResult>.VisitQueryJoinClause(QueryJoinClause queryJoinClause)
3588
// join v in expr on onExpr equals equalsExpr [into g]
3589
ResolveResult inResult = null;
3590
ResolveResult expr = Resolve(queryJoinClause.InExpression);
3592
if (queryJoinClause.Type.IsNull) {
3593
variableType = GetTypeForQueryVariable(expr.Type);
3596
variableType = ResolveType(queryJoinClause.Type);
3598
// resolve the .Cast<>() call
3599
ResolveResult methodGroup = resolver.ResolveMemberAccess(expr, "Cast", new[] { variableType }, NameLookupMode.InvocationTarget);
3600
inResult = resolver.ResolveInvocation(methodGroup, new ResolveResult[0]);
3603
// resolve the 'On' expression in a context that contains only the previously existing range variables:
3604
// (before adding any variable)
3605
ResolveResult onResult = Resolve(queryJoinClause.OnExpression);
3607
// scan the 'Equals' expression in a context that contains only the variable 'v'
3608
CSharpResolver resolverOutsideQuery = resolver;
3609
resolverOutsideQuery = resolverOutsideQuery.PopBlock(); // pop all variables from the current query expression
3610
IVariable v = MakeVariable(variableType, queryJoinClause.JoinIdentifierToken);
3611
resolverOutsideQuery = resolverOutsideQuery.AddVariable(v);
3612
ResolveResult equalsResult = errorResult;
3613
ResetContext(resolverOutsideQuery, delegate {
3614
equalsResult = Resolve(queryJoinClause.EqualsExpression);
3616
StoreCurrentState(queryJoinClause.JoinIdentifierToken);
3617
StoreResult(queryJoinClause.JoinIdentifierToken, new LocalResolveResult(v));
3619
if (queryJoinClause.IsGroupJoin) {
3620
return ResolveGroupJoin(queryJoinClause, inResult, onResult, equalsResult);
3622
resolver = resolver.AddVariable(v);
3623
if (currentQueryResult != null) {
3624
QuerySelectClause selectClause = GetNextQueryClause(queryJoinClause) as QuerySelectClause;
3625
ResolveResult selectResult;
3626
if (selectClause != null) {
3627
// from ... join ... select - the Join call also performs the Select operation
3628
selectResult = Resolve(selectClause.Expression);
3630
// from .. join ... ... - introduce a transparent identifier
3631
selectResult = MakeTransparentIdentifierResolveResult();
3634
var methodGroup = resolver.ResolveMemberAccess(currentQueryResult, "Join", EmptyList<IType>.Instance);
3635
ResolveResult[] arguments = {
3637
new QueryExpressionLambda(1, onResult),
3638
new QueryExpressionLambda(1, equalsResult),
3639
new QueryExpressionLambda(2, selectResult)
3641
return resolver.ResolveInvocation(methodGroup, arguments);
3648
ResolveResult ResolveGroupJoin(QueryJoinClause queryJoinClause,
3649
ResolveResult inResult, ResolveResult onResult, ResolveResult equalsResult)
3651
Debug.Assert(queryJoinClause.IsGroupJoin);
3653
DomRegion intoIdentifierRegion = MakeRegion(queryJoinClause.IntoIdentifierToken);
3655
// We need to declare the group variable, but it's a bit tricky to determine its type:
3656
// We'll have to resolve the GroupJoin invocation and take a look at the inferred types
3657
// for the lambda given as last parameter.
3658
var methodGroup = resolver.ResolveMemberAccess(currentQueryResult, "GroupJoin", EmptyList<IType>.Instance);
3659
QuerySelectClause selectClause = GetNextQueryClause(queryJoinClause) as QuerySelectClause;
3660
LambdaResolveResult groupJoinLambda;
3661
if (selectClause != null) {
3662
// from ... join ... into g select - the GroupJoin call also performs the Select operation
3663
IParameter[] selectLambdaParameters = {
3664
new DefaultParameter(SpecialType.UnknownType, "<>transparentIdentifier"),
3665
new DefaultParameter(SpecialType.UnknownType, queryJoinClause.IntoIdentifier, region: intoIdentifierRegion)
3667
groupJoinLambda = new ImplicitlyTypedLambda(selectClause, selectLambdaParameters, this);
3669
// from .. join ... ... - introduce a transparent identifier
3670
groupJoinLambda = new QueryExpressionLambda(2, MakeTransparentIdentifierResolveResult());
3673
ResolveResult[] arguments = {
3675
new QueryExpressionLambda(1, onResult),
3676
new QueryExpressionLambda(1, equalsResult),
3679
ResolveResult rr = resolver.ResolveInvocation(methodGroup, arguments);
3680
InvocationResolveResult invocationRR = rr as InvocationResolveResult;
3682
IVariable groupVariable;
3683
if (groupJoinLambda is ImplicitlyTypedLambda) {
3684
var implicitlyTypedLambda = (ImplicitlyTypedLambda)groupJoinLambda;
3686
if (invocationRR != null && invocationRR.Arguments.Count > 0) {
3687
ConversionResolveResult crr = invocationRR.Arguments[invocationRR.Arguments.Count - 1] as ConversionResolveResult;
3689
ProcessConversion(null, crr.Input, crr.Conversion, crr.Type);
3692
implicitlyTypedLambda.EnforceMerge(this);
3693
if (implicitlyTypedLambda.Parameters.Count == 2) {
3694
StoreCurrentState(queryJoinClause.IntoIdentifierToken);
3695
groupVariable = implicitlyTypedLambda.Parameters[1];
3697
groupVariable = null;
3700
Debug.Assert(groupJoinLambda is QueryExpressionLambda);
3702
// Add the variable if the query expression continues after the group join
3703
// (there's no need to do this if there's only a select clause remaining, as
3704
// we already handled that in the ImplicitlyTypedLambda).
3706
// Get the inferred type of the group variable:
3707
IType[] inferredParameterTypes = null;
3708
if (invocationRR != null && invocationRR.Arguments.Count > 0) {
3709
ConversionResolveResult crr = invocationRR.Arguments[invocationRR.Arguments.Count - 1] as ConversionResolveResult;
3710
if (crr != null && crr.Conversion is QueryExpressionLambdaConversion) {
3711
inferredParameterTypes = ((QueryExpressionLambdaConversion)crr.Conversion).ParameterTypes;
3714
if (inferredParameterTypes == null)
3715
inferredParameterTypes = ((QueryExpressionLambda)groupJoinLambda).inferredParameterTypes;
3717
IType groupParameterType;
3718
if (inferredParameterTypes != null && inferredParameterTypes.Length == 2)
3719
groupParameterType = inferredParameterTypes[1];
3721
groupParameterType = SpecialType.UnknownType;
3723
StoreCurrentState(queryJoinClause.IntoIdentifierToken);
3724
groupVariable = MakeVariable(groupParameterType, queryJoinClause.IntoIdentifierToken);
3725
resolver = resolver.AddVariable(groupVariable);
3728
if (groupVariable != null) {
3729
StoreResult(queryJoinClause.IntoIdentifierToken, new LocalResolveResult(groupVariable));
3735
ResolveResult IAstVisitor<ResolveResult>.VisitQueryWhereClause(QueryWhereClause queryWhereClause)
3737
ResolveResult condition = Resolve(queryWhereClause.Condition);
3738
IType boolType = resolver.Compilation.FindType(KnownTypeCode.Boolean);
3739
Conversion conversionToBool = resolver.conversions.ImplicitConversion(condition, boolType);
3740
ProcessConversion(queryWhereClause.Condition, condition, conversionToBool, boolType);
3741
if (currentQueryResult != null) {
3742
if (conversionToBool != Conversion.IdentityConversion && conversionToBool != Conversion.None) {
3743
condition = new ConversionResolveResult(boolType, condition, conversionToBool, resolver.CheckForOverflow);
3746
var methodGroup = resolver.ResolveMemberAccess(currentQueryResult, "Where", EmptyList<IType>.Instance);
3747
ResolveResult[] arguments = { new QueryExpressionLambda(1, condition) };
3748
return resolver.ResolveInvocation(methodGroup, arguments);
3754
ResolveResult IAstVisitor<ResolveResult>.VisitQuerySelectClause(QuerySelectClause querySelectClause)
3756
if (currentQueryResult == null) {
3757
ScanChildren(querySelectClause);
3760
QueryClause previousQueryClause = GetPreviousQueryClause(querySelectClause);
3761
// If the 'select' follows on a 'SelectMany', 'Join' or 'GroupJoin' clause, then the 'select' portion
3762
// was already done as part of the previous clause.
3763
if (((previousQueryClause is QueryFromClause && GetPreviousQueryClause(previousQueryClause) != null))
3764
|| previousQueryClause is QueryJoinClause)
3766
// GroupJoin already scans the following select clause in a different context,
3767
// so we must not scan it again.
3768
if (!(previousQueryClause is QueryJoinClause && ((QueryJoinClause)previousQueryClause).IsGroupJoin))
3769
Scan(querySelectClause.Expression);
3770
return WrapResult(currentQueryResult);
3773
QueryExpression query = querySelectClause.Parent as QueryExpression;
3774
string rangeVariable = GetSingleRangeVariable(query);
3775
if (rangeVariable != null) {
3776
IdentifierExpression ident = ParenthesizedExpression.UnpackParenthesizedExpression(querySelectClause.Expression) as IdentifierExpression;
3777
if (ident != null && ident.Identifier == rangeVariable && !ident.TypeArguments.Any()) {
3778
// selecting the single identifier that is the range variable
3779
if (query.Clauses.Count > 2) {
3780
// only if the query is not degenerate:
3781
// the Select call will be optimized away, so directly return the previous result
3782
Scan(querySelectClause.Expression);
3783
return WrapResult(currentQueryResult);
3788
ResolveResult expr = Resolve(querySelectClause.Expression);
3789
var methodGroup = resolver.ResolveMemberAccess(currentQueryResult, "Select", EmptyList<IType>.Instance);
3790
ResolveResult[] arguments = { new QueryExpressionLambda(1, expr) };
3791
return resolver.ResolveInvocation(methodGroup, arguments);
3795
/// Gets the name of the range variable in the specified query.
3796
/// If the query has multiple range variables, this method returns null.
3798
string GetSingleRangeVariable(QueryExpression query)
3802
foreach (QueryClause clause in query.Clauses.Skip(1)) {
3803
if (clause is QueryFromClause || clause is QueryJoinClause || clause is QueryLetClause) {
3804
// query has more than 1 range variable
3808
QueryFromClause fromClause = query.Clauses.FirstOrDefault() as QueryFromClause;
3809
if (fromClause != null)
3810
return fromClause.Identifier;
3811
QueryContinuationClause continuationClause = query.Clauses.FirstOrDefault() as QueryContinuationClause;
3812
if (continuationClause != null)
3813
return continuationClause.Identifier;
3817
ResolveResult IAstVisitor<ResolveResult>.VisitQueryGroupClause(QueryGroupClause queryGroupClause)
3819
if (currentQueryResult == null) {
3820
ScanChildren(queryGroupClause);
3824
// ... group projection by key
3825
ResolveResult projection = Resolve(queryGroupClause.Projection);
3826
ResolveResult key = Resolve(queryGroupClause.Key);
3828
var methodGroup = resolver.ResolveMemberAccess(currentQueryResult, "GroupBy", EmptyList<IType>.Instance);
3829
ResolveResult[] arguments = {
3830
new QueryExpressionLambda(1, key),
3831
new QueryExpressionLambda(1, projection)
3833
return resolver.ResolveInvocation(methodGroup, arguments);
3836
ResolveResult IAstVisitor<ResolveResult>.VisitQueryOrderClause(QueryOrderClause queryOrderClause)
3838
foreach (QueryOrdering ordering in queryOrderClause.Orderings) {
3839
currentQueryResult = Resolve(ordering);
3841
return WrapResult(currentQueryResult);
3844
ResolveResult IAstVisitor<ResolveResult>.VisitQueryOrdering(QueryOrdering queryOrdering)
3846
if (currentQueryResult == null) {
3847
ScanChildren(queryOrdering);
3850
// ... orderby sortKey [descending]
3851
ResolveResult sortKey = Resolve(queryOrdering.Expression);
3853
QueryOrderClause parentClause = queryOrdering.Parent as QueryOrderClause;
3854
bool isFirst = (parentClause == null || parentClause.Orderings.FirstOrDefault() == queryOrdering);
3855
string methodName = isFirst ? "OrderBy" : "ThenBy";
3856
if (queryOrdering.Direction == QueryOrderingDirection.Descending)
3857
methodName += "Descending";
3859
var methodGroup = resolver.ResolveMemberAccess(currentQueryResult, methodName, EmptyList<IType>.Instance);
3860
ResolveResult[] arguments = {
3861
new QueryExpressionLambda(1, sortKey),
3863
return resolver.ResolveInvocation(methodGroup, arguments);
3867
#region Constructor Initializer
3868
ResolveResult IAstVisitor<ResolveResult>.VisitConstructorInitializer(ConstructorInitializer constructorInitializer)
3870
ResolveResult target;
3871
if (constructorInitializer.ConstructorInitializerType == ConstructorInitializerType.Base) {
3872
target = resolver.ResolveBaseReference();
3874
target = resolver.ResolveThisReference();
3876
string[] argumentNames;
3877
ResolveResult[] arguments = GetArguments(constructorInitializer.Arguments, out argumentNames);
3878
ResolveResult rr = resolver.ResolveObjectCreation(target.Type, arguments, argumentNames, allowProtectedAccess: true);
3879
ProcessInvocationResult(null, constructorInitializer.Arguments, rr);
3886
ResolveResult IAstVisitor<ResolveResult>.VisitIdentifier(Identifier identifier)
3891
ResolveResult IAstVisitor<ResolveResult>.VisitComment (Comment comment)
3896
ResolveResult IAstVisitor<ResolveResult>.VisitNewLine (NewLineNode comment)
3901
ResolveResult IAstVisitor<ResolveResult>.VisitWhitespace(WhitespaceNode whitespaceNode)
3906
ResolveResult IAstVisitor<ResolveResult>.VisitText(TextNode textNode)
3911
ResolveResult IAstVisitor<ResolveResult>.VisitPreProcessorDirective (PreProcessorDirective preProcessorDirective)
3916
ResolveResult IAstVisitor<ResolveResult>.VisitCSharpTokenNode(CSharpTokenNode cSharpTokenNode)
3921
ResolveResult IAstVisitor<ResolveResult>.VisitArraySpecifier(ArraySpecifier arraySpecifier)
3926
ResolveResult IAstVisitor<ResolveResult>.VisitPatternPlaceholder(AstNode placeholder, ICSharpCode.NRefactory.PatternMatching.Pattern pattern)
3931
// Nodes where we just need to visit the children:
3932
ResolveResult IAstVisitor<ResolveResult>.VisitAccessor(Accessor accessor)
3934
ScanChildren(accessor);
3938
ResolveResult IAstVisitor<ResolveResult>.VisitSwitchSection(SwitchSection switchSection)
3940
ScanChildren(switchSection);
3944
ResolveResult IAstVisitor<ResolveResult>.VisitCaseLabel(CaseLabel caseLabel)
3946
ScanChildren(caseLabel);
3950
ResolveResult IAstVisitor<ResolveResult>.VisitConstraint(Constraint constraint)
3952
ScanChildren(constraint);
3957
#region Documentation Reference
3958
ResolveResult IAstVisitor<ResolveResult>.VisitDocumentationReference(DocumentationReference documentationReference)
3960
// Resolve child nodes:
3961
ITypeDefinition declaringTypeDef;
3962
if (documentationReference.DeclaringType.IsNull)
3963
declaringTypeDef = resolver.CurrentTypeDefinition;
3965
declaringTypeDef = ResolveType(documentationReference.DeclaringType).GetDefinition();
3966
IType[] typeArguments = documentationReference.TypeArguments.Select(ResolveType).ToArray();
3967
IType conversionOperatorReturnType = ResolveType(documentationReference.ConversionOperatorReturnType);
3968
IParameter[] parameters = documentationReference.Parameters.Select(ResolveXmlDocParameter).ToArray();
3970
if (documentationReference.EntityType == EntityType.TypeDefinition) {
3971
if (declaringTypeDef != null)
3972
return new TypeResolveResult(declaringTypeDef);
3977
if (documentationReference.EntityType == EntityType.None) {
3978
// might be a type, member or ctor
3979
string memberName = documentationReference.MemberName;
3981
if (documentationReference.DeclaringType.IsNull) {
3982
rr = resolver.LookupSimpleNameOrTypeName(memberName, typeArguments, NameLookupMode.Expression);
3984
var target = Resolve(documentationReference.DeclaringType);
3985
rr = resolver.ResolveMemberAccess(target, memberName, typeArguments);
3987
// reduce to definition:
3990
} else if (rr is TypeResolveResult) {
3991
var typeDef = rr.Type.GetDefinition();
3992
if (typeDef == null)
3994
if (documentationReference.HasParameterList) {
3995
var ctors = typeDef.GetConstructors(options: GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions);
3996
return FindByParameters(ctors, parameters);
3998
return new TypeResolveResult(typeDef);
4000
} else if (rr is MemberResolveResult) {
4001
var mrr = (MemberResolveResult)rr;
4002
return new MemberResolveResult(null, mrr.Member.MemberDefinition);
4003
} else if (rr is MethodGroupResolveResult) {
4004
var mgrr = (MethodGroupResolveResult)rr;
4005
var methods = mgrr.MethodsGroupedByDeclaringType.Reverse()
4006
.SelectMany(ml => ml.Select(m => (IParameterizedMember)m.MemberDefinition));
4007
return FindByParameters(methods, parameters);
4012
// Indexer or operator
4013
if (declaringTypeDef == null)
4015
if (documentationReference.EntityType == EntityType.Indexer) {
4016
var indexers = declaringTypeDef.Properties.Where(p => p.IsIndexer && !p.IsExplicitInterfaceImplementation);
4017
return FindByParameters(indexers, parameters);
4018
} else if (documentationReference.EntityType == EntityType.Operator) {
4019
var opType = documentationReference.OperatorType;
4020
string memberName = OperatorDeclaration.GetName(opType);
4021
var methods = declaringTypeDef.Methods.Where(m => m.IsOperator && m.Name == memberName);
4022
if (opType == OperatorType.Implicit || opType == OperatorType.Explicit) {
4023
// conversion operator
4024
foreach (var method in methods) {
4025
if (ParameterListComparer.Instance.Equals(method.Parameters, parameters)) {
4026
if (method.ReturnType.Equals(conversionOperatorReturnType))
4027
return new MemberResolveResult(null, method);
4030
return new MemberResolveResult(null, methods.FirstOrDefault());
4032
// not a conversion operator
4033
return FindByParameters(methods, parameters);
4036
throw new NotSupportedException(); // unknown entity type
4040
IParameter ResolveXmlDocParameter(ParameterDeclaration p)
4042
var lrr = Resolve(p) as LocalResolveResult;
4043
if (lrr != null && lrr.IsParameter)
4044
return (IParameter)lrr.Variable;
4046
return new DefaultParameter(SpecialType.UnknownType, string.Empty);
4049
ResolveResult FindByParameters(IEnumerable<IParameterizedMember> methods, IList<IParameter> parameters)
4051
foreach (var method in methods) {
4052
if (ParameterListComparer.Instance.Equals(method.Parameters, parameters))
4053
return new MemberResolveResult(null, method);
4055
return new MemberResolveResult(null, methods.FirstOrDefault());