1
ļ»æ// Copyright (c) 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;
30
using ICSharpCode.NRefactory.Utils;
32
namespace ICSharpCode.NRefactory.CSharp.Resolver
35
/// Traverses the DOM and resolves expressions.
38
/// The ResolveVisitor does two jobs at the same time: it tracks the resolve context (properties on CSharpResolver)
39
/// and it resolves the expressions visited.
40
/// To allow using the context tracking without having to resolve every expression in the file (e.g. when you want to resolve
41
/// only a single node deep within the DOM), you can use the <see cref="IResolveVisitorNavigator"/> interface.
42
/// The navigator allows you to switch the between scanning mode and resolving mode.
43
/// In scanning mode, the context is tracked (local variables registered etc.), but nodes are not resolved.
44
/// While scanning, the navigator will get asked about every node that the resolve visitor is about to enter.
45
/// This allows the navigator whether to keep scanning, whether switch to resolving mode, or whether to completely skip the
46
/// subtree rooted at that node.
48
/// In resolving mode, the context is tracked and nodes will be resolved.
49
/// The resolve visitor may decide that it needs to resolve other nodes as well in order to resolve the current node.
50
/// In this case, those nodes will be resolved automatically, without asking the navigator interface.
51
/// For child nodes that are not essential to resolving, the resolve visitor will switch back to scanning mode (and thus will
52
/// ask the navigator for further instructions).
54
/// Moreover, there is the <c>ResolveAll</c> mode - it works similar to resolving mode, but will not switch back to scanning mode.
55
/// The whole subtree will be resolved without notifying the navigator.
57
sealed class ResolveVisitor : IAstVisitor<ResolveResult>
59
// The ResolveVisitor is also responsible for handling lambda expressions.
61
static readonly ResolveResult errorResult = ErrorResolveResult.UnknownError;
62
readonly ResolveResult voidResult;
64
CSharpResolver resolver;
65
/// <summary>Resolve result of the current LINQ query.</summary>
66
/// <remarks>We do not have to put this into the stored state (resolver) because
67
/// query expressions are always resolved in a single operation.</remarks>
68
ResolveResult currentQueryResult;
69
readonly CSharpParsedFile parsedFile;
70
readonly Dictionary<AstNode, ResolveResult> resolveResultCache = new Dictionary<AstNode, ResolveResult>();
71
readonly Dictionary<AstNode, CSharpResolver> resolverBeforeDict = new Dictionary<AstNode, CSharpResolver>();
72
readonly Dictionary<AstNode, CSharpResolver> resolverAfterDict = new Dictionary<AstNode, CSharpResolver>();
73
readonly Dictionary<Expression, ConversionWithTargetType> conversionDict = new Dictionary<Expression, ConversionWithTargetType>();
75
internal struct ConversionWithTargetType
77
public readonly Conversion Conversion;
78
public readonly IType TargetType;
80
public ConversionWithTargetType(Conversion conversion, IType targetType)
82
this.Conversion = conversion;
83
this.TargetType = targetType;
87
IResolveVisitorNavigator navigator;
89
List<LambdaBase> undecidedLambdas;
90
internal CancellationToken cancellationToken;
93
static readonly IResolveVisitorNavigator skipAllNavigator = new ConstantModeResolveVisitorNavigator(ResolveVisitorNavigationMode.Skip, null);
96
/// Creates a new ResolveVisitor instance.
98
/// <param name="resolver">
99
/// The CSharpResolver, describing the initial resolve context.
100
/// If you visit a whole CompilationUnit with the resolve visitor, you can simply pass
101
/// <c>new CSharpResolver(typeResolveContext)</c> without setting up the context.
102
/// If you only visit a subtree, you need to pass a CSharpResolver initialized to the context for that subtree.
104
/// <param name="parsedFile">
105
/// Result of the <see cref="TypeSystemConvertVisitor"/> for the file being passed. This is used for setting up the context on the resolver.
106
/// You may pass <c>null</c> if you are only visiting a part of a method body and have already set up the context in the <paramref name="resolver"/>.
108
public ResolveVisitor(CSharpResolver resolver, CSharpParsedFile parsedFile)
110
if (resolver == null)
111
throw new ArgumentNullException("resolver");
112
this.resolver = resolver;
113
this.parsedFile = parsedFile;
114
this.navigator = skipAllNavigator;
115
this.voidResult = new ResolveResult(resolver.Compilation.FindType(KnownTypeCode.Void));
118
internal void SetNavigator(IResolveVisitorNavigator navigator)
120
this.navigator = navigator ?? skipAllNavigator;
126
/// Resets the visitor to the stored position, runs the action, and then reverts the visitor to the previous position.
128
void ResetContext(CSharpResolver storedContext, Action action)
130
var oldResolverEnabled = this.resolverEnabled;
131
var oldResolver = this.resolver;
132
var oldQueryResult = this.currentQueryResult;
134
this.resolverEnabled = false;
135
this.resolver = storedContext;
136
this.currentQueryResult = null;
140
this.resolverEnabled = oldResolverEnabled;
141
this.resolver = oldResolver;
142
this.currentQueryResult = oldQueryResult;
147
#region Scan / Resolve
149
/// Scans the AST rooted at the given node.
151
public void Scan(AstNode node)
153
if (node == null || node.IsNull)
155
switch (node.NodeType) {
157
case NodeType.Whitespace:
158
return; // skip tokens, identifiers, comments, etc.
160
// don't Scan again if the node was already resolved
161
if (resolveResultCache.ContainsKey(node)) {
162
// Restore state change caused by this node:
163
CSharpResolver newResolver;
164
if (resolverAfterDict.TryGetValue(node, out newResolver))
165
resolver = newResolver;
169
var mode = navigator.Scan(node);
171
case ResolveVisitorNavigationMode.Skip:
172
if (node is VariableDeclarationStatement || node is SwitchSection) {
173
// Enforce scanning of variable declarations.
174
goto case ResolveVisitorNavigationMode.Scan;
176
StoreCurrentState(node);
178
case ResolveVisitorNavigationMode.Scan:
179
bool oldResolverEnabled = resolverEnabled;
180
var oldResolver = resolver;
181
resolverEnabled = false;
182
StoreCurrentState(node);
183
ResolveResult result = node.AcceptVisitor(this);
184
if (result != null) {
185
// If the node was resolved, store the result even though it wasn't requested.
186
// This is necessary so that Visit-methods that decide to always resolve are
187
// guaranteed to get called only once.
188
// This is used for lambda registration.
189
StoreResult(node, result);
190
if (resolver != oldResolver) {
191
// The node changed the resolver state:
192
resolverAfterDict.Add(node, resolver);
194
cancellationToken.ThrowIfCancellationRequested();
196
resolverEnabled = oldResolverEnabled;
198
case ResolveVisitorNavigationMode.Resolve:
202
throw new InvalidOperationException("Invalid value for ResolveVisitorNavigationMode");
207
/// Equivalent to 'Scan', but also resolves the node at the same time.
208
/// This method should be only used if the CSharpResolver passed to the ResolveVisitor was manually set
209
/// to the correct state.
210
/// Otherwise, use <c>resolver.Scan(compilationUnit); var result = resolver.GetResolveResult(node);</c>
213
/// This method now is internal, because it is difficult to use correctly.
214
/// Users of the public API should use Scan()+GetResolveResult() instead.
216
internal ResolveResult Resolve(AstNode node)
218
if (node == null || node.IsNull)
220
bool oldResolverEnabled = resolverEnabled;
221
resolverEnabled = true;
222
ResolveResult result;
223
if (!resolveResultCache.TryGetValue(node, out result)) {
224
cancellationToken.ThrowIfCancellationRequested();
225
StoreCurrentState(node);
226
var oldResolver = resolver;
227
result = node.AcceptVisitor(this) ?? errorResult;
228
StoreResult(node, result);
229
if (resolver != oldResolver) {
230
// The node changed the resolver state:
231
resolverAfterDict.Add(node, resolver);
234
resolverEnabled = oldResolverEnabled;
238
IType ResolveType(AstType type)
240
return Resolve(type).Type;
243
void StoreCurrentState(AstNode node)
245
// It's possible that we re-visit an expression that we scanned over earlier,
246
// so we might have to overwrite an existing state.
249
CSharpResolver oldResolver;
250
if (resolverBeforeDict.TryGetValue(node, out oldResolver)) {
251
Debug.Assert(oldResolver.LocalVariables.SequenceEqual(resolver.LocalVariables));
255
resolverBeforeDict[node] = resolver;
258
void StoreResult(AstNode node, ResolveResult result)
260
Debug.Assert(result != null);
263
Log.WriteLine("Resolved '{0}' to {1}", node, result);
264
Debug.Assert(!CSharpAstResolver.IsUnresolvableNode(node));
265
// The state should be stored before the result is.
266
Debug.Assert(resolverBeforeDict.ContainsKey(node));
267
// Don't store results twice.
268
Debug.Assert(!resolveResultCache.ContainsKey(node));
269
resolveResultCache[node] = result;
270
if (navigator != null)
271
navigator.Resolved(node, result);
274
void ScanChildren(AstNode node)
276
for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) {
282
#region Process Conversions
283
sealed class AnonymousFunctionConversion : Conversion
285
public readonly IType ReturnType;
286
public readonly ExplicitlyTypedLambda ExplicitlyTypedLambda;
287
public readonly LambdaTypeHypothesis Hypothesis;
288
readonly bool isValid;
290
public AnonymousFunctionConversion(IType returnType, LambdaTypeHypothesis hypothesis, bool isValid)
292
if (returnType == null)
293
throw new ArgumentNullException("returnType");
294
this.ReturnType = returnType;
295
this.Hypothesis = hypothesis;
296
this.isValid = isValid;
299
public AnonymousFunctionConversion(IType returnType, ExplicitlyTypedLambda explicitlyTypedLambda, bool isValid)
301
if (returnType == null)
302
throw new ArgumentNullException("returnType");
303
this.ReturnType = returnType;
304
this.ExplicitlyTypedLambda = explicitlyTypedLambda;
305
this.isValid = isValid;
308
public override bool IsValid {
309
get { return isValid; }
312
public override bool IsImplicit {
316
public override bool IsAnonymousFunctionConversion {
322
/// Convert 'rr' to the target type using the specified conversion.
324
void ProcessConversion(Expression expr, ResolveResult rr, Conversion conversion, IType targetType)
326
AnonymousFunctionConversion afc = conversion as AnonymousFunctionConversion;
328
Log.WriteLine("Processing conversion of anonymous function to " + targetType + "...");
331
if (afc.Hypothesis != null)
332
afc.Hypothesis.MergeInto(this, afc.ReturnType);
333
if (afc.ExplicitlyTypedLambda != null)
334
afc.ExplicitlyTypedLambda.ApplyReturnType(this, afc.ReturnType);
337
if (expr != null && !expr.IsNull && conversion != Conversion.IdentityConversion) {
338
navigator.ProcessConversion(expr, rr, conversion, targetType);
339
conversionDict[expr] = new ConversionWithTargetType(conversion, targetType);
343
void ImportConversions(ResolveVisitor childVisitor)
345
foreach (var pair in childVisitor.conversionDict) {
346
conversionDict.Add(pair.Key, pair.Value);
347
navigator.ProcessConversion(pair.Key, resolveResultCache[pair.Key], pair.Value.Conversion, pair.Value.TargetType);
352
/// Convert 'rr' to the target type.
354
void ProcessConversion(Expression expr, ResolveResult rr, IType targetType)
356
if (expr == null || expr.IsNull)
358
ProcessConversion(expr, rr, resolver.conversions.ImplicitConversion(rr, targetType), targetType);
362
/// Resolves the specified expression and processes the conversion to targetType.
364
void ResolveAndProcessConversion(Expression expr, IType targetType)
366
if (targetType.Kind == TypeKind.Unknown || targetType.Kind == TypeKind.Void) {
367
// no need to resolve the expression right now
370
ProcessConversion(expr, Resolve(expr), targetType);
374
void ProcessConversionResult(Expression expr, ConversionResolveResult rr)
377
ProcessConversion(expr, rr.Input, rr.Conversion, rr.Type);
380
void ProcessConversionResults(IEnumerable<Expression> expr, IEnumerable<ResolveResult> conversionResolveResults)
382
Debug.Assert(expr.Count() == conversionResolveResults.Count());
383
using (var e1 = expr.GetEnumerator()) {
384
using (var e2 = conversionResolveResults.GetEnumerator()) {
385
while (e1.MoveNext() && e2.MoveNext()) {
386
ProcessConversionResult(e1.Current, e2.Current as ConversionResolveResult);
392
void ProcessConversionsInInvocation(Expression target, IEnumerable<Expression> arguments, CSharpInvocationResolveResult invocation)
394
if (invocation == null)
397
if (invocation.IsExtensionMethodInvocation) {
398
Debug.Assert(arguments.Count() + 1 == invocation.Arguments.Count);
399
ProcessConversionResult(target, invocation.Arguments[0] as ConversionResolveResult);
402
Debug.Assert(arguments.Count() == invocation.Arguments.Count);
404
foreach (Expression arg in arguments) {
405
NamedArgumentExpression nae = arg as NamedArgumentExpression;
407
ProcessConversionResult(nae.Expression, invocation.Arguments[i++] as ConversionResolveResult);
409
ProcessConversionResult(arg, invocation.Arguments[i++] as ConversionResolveResult);
414
#region GetResolveResult
416
/// Gets the resolve result for the specified node.
417
/// If the node was not resolved by the navigator, this method will resolve it.
419
public ResolveResult GetResolveResult(AstNode node)
421
Debug.Assert(!CSharpAstResolver.IsUnresolvableNode(node));
423
MergeUndecidedLambdas();
424
ResolveResult result;
425
if (resolveResultCache.TryGetValue(node, out result))
429
CSharpResolver storedResolver = GetPreviouslyScannedContext(node, out parent);
433
navigator = new NodeListResolveVisitorNavigator(node);
434
Debug.Assert(!resolverEnabled);
436
navigator = skipAllNavigator;
439
MergeUndecidedLambdas();
440
return resolveResultCache[node];
443
CSharpResolver GetPreviouslyScannedContext(AstNode node, out AstNode parent)
446
CSharpResolver storedResolver;
447
while (!resolverBeforeDict.TryGetValue(parent, out storedResolver)) {
448
parent = parent.Parent;
450
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?");
452
return storedResolver;
456
/// Gets the resolver state in front of the specified node.
457
/// If the node was not visited by a previous scanning process, the
458
/// AST will be scanned again to determine the state.
460
public CSharpResolver GetResolverStateBefore(AstNode node)
462
MergeUndecidedLambdas();
464
if (resolverBeforeDict.TryGetValue(node, out r))
468
CSharpResolver storedResolver = GetPreviouslyScannedContext(node, out parent);
472
navigator = new NodeListResolveVisitorNavigator(new[] { node }, scanOnly: true);
473
Debug.Assert(!resolverEnabled);
474
// parent might already be resolved if 'node' is an unresolvable node
476
navigator = skipAllNavigator;
479
MergeUndecidedLambdas();
480
while (node != null) {
481
if (resolverBeforeDict.TryGetValue(node, out r))
488
public CSharpResolver GetResolverStateAfter(AstNode node)
490
// Resolve the node to fill the resolverAfterDict
491
GetResolveResult(node);
492
CSharpResolver result;
493
if (resolverAfterDict.TryGetValue(node, out result))
496
return GetResolverStateBefore(node);
499
public ConversionWithTargetType GetConversionWithTargetType(Expression expr)
501
GetResolverStateBefore(expr);
502
ResolveParentForConversion(expr);
503
ConversionWithTargetType result;
504
if (conversionDict.TryGetValue(expr, out result)) {
507
ResolveResult rr = GetResolveResult(expr);
508
return new ConversionWithTargetType(Conversion.IdentityConversion, rr.Type);
513
#region Track UsingScope
514
ResolveResult IAstVisitor<ResolveResult>.VisitCompilationUnit(CompilationUnit unit)
516
CSharpResolver previousResolver = resolver;
518
if (parsedFile != null) {
519
resolver = resolver.WithCurrentUsingScope(parsedFile.RootUsingScope.Resolve(resolver.Compilation));
521
var cv = new TypeSystemConvertVisitor(unit.FileName ?? string.Empty);
522
ApplyVisitorToUsings(cv, unit.Children);
523
PushUsingScope(cv.ParsedFile.RootUsingScope);
528
resolver = previousResolver;
532
void ApplyVisitorToUsings(TypeSystemConvertVisitor visitor, IEnumerable<AstNode> children)
534
foreach (var child in children) {
535
if (child is ExternAliasDeclaration || child is UsingDeclaration || child is UsingAliasDeclaration) {
536
child.AcceptVisitor(visitor);
541
void PushUsingScope(UsingScope usingScope)
544
resolver = resolver.WithCurrentUsingScope(new ResolvedUsingScope(resolver.CurrentTypeResolveContext, usingScope));
547
ResolveResult IAstVisitor<ResolveResult>.VisitNamespaceDeclaration(NamespaceDeclaration namespaceDeclaration)
549
CSharpResolver previousResolver = resolver;
551
if (parsedFile != null) {
552
resolver = resolver.WithCurrentUsingScope(parsedFile.GetUsingScope(namespaceDeclaration.StartLocation).Resolve(resolver.Compilation));
554
string fileName = namespaceDeclaration.GetRegion().FileName ?? string.Empty;
555
// Fetch parent using scope
556
// Create root using scope if necessary
557
if (resolver.CurrentUsingScope == null)
558
PushUsingScope(new UsingScope());
560
// Create child using scope
561
DomRegion region = namespaceDeclaration.GetRegion();
562
var identifiers = namespaceDeclaration.Identifiers.ToList();
563
// For all but the last identifier:
564
UsingScope usingScope;
565
for (int i = 0; i < identifiers.Count - 1; i++) {
566
usingScope = new UsingScope(resolver.CurrentUsingScope.UnresolvedUsingScope, identifiers[i].Name);
567
usingScope.Region = region;
568
PushUsingScope(usingScope);
571
usingScope = new UsingScope(resolver.CurrentUsingScope.UnresolvedUsingScope, identifiers.Last().Name);
572
usingScope.Region = region;
573
var cv = new TypeSystemConvertVisitor(new CSharpParsedFile(region.FileName ?? string.Empty), usingScope);
574
ApplyVisitorToUsings(cv, namespaceDeclaration.Children);
575
PushUsingScope(usingScope);
577
ScanChildren(namespaceDeclaration);
578
// merge undecided lambdas before leaving the using scope so that
579
// the resolver can make better use of its cache
580
MergeUndecidedLambdas();
581
if (resolver.CurrentUsingScope != null && resolver.CurrentUsingScope.Namespace != null)
582
return new NamespaceResolveResult(resolver.CurrentUsingScope.Namespace);
586
resolver = previousResolver;
591
#region Track CurrentTypeDefinition
592
ResolveResult VisitTypeOrDelegate(AstNode typeDeclaration, string name, int typeParameterCount)
594
CSharpResolver previousResolver = resolver;
596
ITypeDefinition newTypeDefinition = null;
597
if (resolver.CurrentTypeDefinition != null) {
598
int totalTypeParameterCount = resolver.CurrentTypeDefinition.TypeParameterCount + typeParameterCount;
599
foreach (ITypeDefinition nestedType in resolver.CurrentTypeDefinition.NestedTypes) {
600
if (nestedType.Name == name && nestedType.TypeParameterCount == totalTypeParameterCount) {
601
newTypeDefinition = nestedType;
605
} else if (resolver.CurrentUsingScope != null) {
606
newTypeDefinition = resolver.CurrentUsingScope.Namespace.GetTypeDefinition(name, typeParameterCount);
608
if (newTypeDefinition != null)
609
resolver = resolver.WithCurrentTypeDefinition(newTypeDefinition);
611
ScanChildren(typeDeclaration);
613
// merge undecided lambdas before leaving the type definition so that
614
// the resolver can make better use of its cache
615
MergeUndecidedLambdas();
617
return newTypeDefinition != null ? new TypeResolveResult(newTypeDefinition) : errorResult;
619
resolver = previousResolver;
623
ResolveResult IAstVisitor<ResolveResult>.VisitTypeDeclaration(TypeDeclaration typeDeclaration)
625
return VisitTypeOrDelegate(typeDeclaration, typeDeclaration.Name, typeDeclaration.TypeParameters.Count);
628
ResolveResult IAstVisitor<ResolveResult>.VisitDelegateDeclaration(DelegateDeclaration delegateDeclaration)
630
return VisitTypeOrDelegate(delegateDeclaration, delegateDeclaration.Name, delegateDeclaration.TypeParameters.Count);
634
#region Track CurrentMember
635
ResolveResult IAstVisitor<ResolveResult>.VisitFieldDeclaration(FieldDeclaration fieldDeclaration)
637
return VisitFieldOrEventDeclaration(fieldDeclaration, EntityType.Field);
640
ResolveResult IAstVisitor<ResolveResult>.VisitFixedFieldDeclaration(FixedFieldDeclaration fixedFieldDeclaration)
642
return VisitFieldOrEventDeclaration(fixedFieldDeclaration, EntityType.Field);
645
ResolveResult IAstVisitor<ResolveResult>.VisitEventDeclaration(EventDeclaration eventDeclaration)
647
return VisitFieldOrEventDeclaration(eventDeclaration, EntityType.Event);
650
ResolveResult VisitFieldOrEventDeclaration(EntityDeclaration fieldOrEventDeclaration, EntityType entityType)
652
//int initializerCount = fieldOrEventDeclaration.GetChildrenByRole(Roles.Variable).Count;
653
CSharpResolver oldResolver = resolver;
654
for (AstNode node = fieldOrEventDeclaration.FirstChild; node != null; node = node.NextSibling) {
655
if (node.Role == Roles.Variable) {
657
if (parsedFile != null) {
658
member = GetMemberFromLocation(node.StartLocation);
660
string name = ((VariableInitializer)node).Name;
661
member = AbstractUnresolvedMember.Resolve(resolver.CurrentTypeResolveContext, entityType, name);
663
resolver = resolver.WithCurrentMember(member);
667
resolver = oldResolver;
675
IMember GetMemberFromLocation(TextLocation location)
677
ITypeDefinition typeDef = resolver.CurrentTypeDefinition;
680
return typeDef.GetMembers(
681
delegate (IUnresolvedMember m) {
682
if (m.ParsedFile != parsedFile)
684
DomRegion region = m.Region;
685
return !region.IsEmpty && region.Begin <= location && region.End > location;
687
GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions
691
ResolveResult IAstVisitor<ResolveResult>.VisitVariableInitializer(VariableInitializer variableInitializer)
693
// Within the variable initializer, the newly declared variable is not yet available:
694
var resolverWithVariable = resolver;
695
if (variableInitializer.Parent is VariableDeclarationStatement)
696
resolver = resolver.PopLastVariable();
698
ArrayInitializerExpression aie = variableInitializer.Initializer as ArrayInitializerExpression;
699
if (resolverEnabled || aie != null) {
700
ResolveResult result = errorResult;
701
if (variableInitializer.Parent is FieldDeclaration || variableInitializer.Parent is EventDeclaration) {
702
if (resolver.CurrentMember != null) {
703
result = new MemberResolveResult(null, resolver.CurrentMember, false);
706
string identifier = variableInitializer.Name;
707
foreach (IVariable v in resolverWithVariable.LocalVariables) {
708
if (v.Name == identifier) {
709
result = new LocalResolveResult(v);
714
ArrayType arrayType = result.Type as ArrayType;
715
if (aie != null && arrayType != null) {
716
StoreCurrentState(aie);
717
List<Expression> initializerElements = new List<Expression>();
718
UnpackArrayInitializer(initializerElements, aie, arrayType.Dimensions, true);
719
ResolveResult[] initializerElementResults = new ResolveResult[initializerElements.Count];
720
for (int i = 0; i < initializerElementResults.Length; i++) {
721
initializerElementResults[i] = Resolve(initializerElements[i]);
723
var arrayCreation = resolver.ResolveArrayCreation(arrayType.ElementType, arrayType.Dimensions, null, initializerElementResults);
724
StoreResult(aie, arrayCreation);
725
ProcessConversionResults(initializerElements, arrayCreation.InitializerElements);
726
} else if (variableInitializer.Parent is FixedStatement) {
727
var initRR = Resolve(variableInitializer.Initializer);
728
PointerType pointerType;
729
if (initRR.Type.Kind == TypeKind.Array) {
730
pointerType = new PointerType(((ArrayType)initRR.Type).ElementType);
731
} else if (ReflectionHelper.GetTypeCode(initRR.Type) == TypeCode.String) {
732
pointerType = new PointerType(resolver.Compilation.FindType(KnownTypeCode.Char));
735
ProcessConversion(variableInitializer.Initializer, initRR, result.Type);
737
if (pointerType != null) {
738
var conversion = resolver.conversions.ImplicitConversion(pointerType, result.Type);
739
if (conversion.IsIdentityConversion)
740
conversion = Conversion.ImplicitPointerConversion;
741
ProcessConversion(variableInitializer.Initializer, initRR, conversion, result.Type);
744
ResolveAndProcessConversion(variableInitializer.Initializer, result.Type);
746
resolver = resolverWithVariable;
749
Scan(variableInitializer.Initializer);
750
resolver = resolverWithVariable;
755
ResolveResult IAstVisitor<ResolveResult>.VisitFixedVariableInitializer(FixedVariableInitializer fixedVariableInitializer)
757
if (resolverEnabled) {
758
ResolveResult result = errorResult;
759
if (resolver.CurrentMember != null) {
760
result = new MemberResolveResult(null, resolver.CurrentMember, false);
762
ResolveAndProcessConversion(fixedVariableInitializer.CountExpression, resolver.Compilation.FindType(KnownTypeCode.Int32));
765
ScanChildren(fixedVariableInitializer);
770
ResolveResult VisitMethodMember(EntityDeclaration memberDeclaration)
772
CSharpResolver oldResolver = resolver;
775
if (parsedFile != null) {
776
member = GetMemberFromLocation(memberDeclaration.StartLocation);
778
// Re-discover the method:
779
EntityType entityType = memberDeclaration.EntityType;
780
var parameterTypes = TypeSystemConvertVisitor.GetParameterTypes(memberDeclaration.GetChildrenByRole(Roles.Parameter));
781
if (entityType == EntityType.Constructor) {
782
string name = memberDeclaration.HasModifier(Modifiers.Static) ? ".cctor" : ".ctor";
783
member = AbstractUnresolvedMember.Resolve(
784
resolver.CurrentTypeResolveContext, entityType, name,
785
parameterTypeReferences: parameterTypes);
786
} else if (entityType == EntityType.Destructor) {
787
member = AbstractUnresolvedMember.Resolve(resolver.CurrentTypeResolveContext, entityType, "Finalize");
789
string[] typeParameterNames = memberDeclaration.GetChildrenByRole(Roles.TypeParameter).Select(tp => tp.Name).ToArray();
790
AstType explicitInterfaceAstType = memberDeclaration.GetChildByRole(EntityDeclaration.PrivateImplementationTypeRole);
791
ITypeReference explicitInterfaceType = null;
792
if (!explicitInterfaceAstType.IsNull) {
793
explicitInterfaceType = explicitInterfaceAstType.ToTypeReference();
795
member = AbstractUnresolvedMember.Resolve(
796
resolver.CurrentTypeResolveContext, entityType, memberDeclaration.Name,
797
explicitInterfaceType, typeParameterNames, parameterTypes);
800
resolver = resolver.WithCurrentMember(member);
801
ScanChildren(memberDeclaration);
804
return new MemberResolveResult(null, member, false);
808
resolver = oldResolver;
812
ResolveResult IAstVisitor<ResolveResult>.VisitMethodDeclaration(MethodDeclaration methodDeclaration)
814
return VisitMethodMember(methodDeclaration);
817
ResolveResult IAstVisitor<ResolveResult>.VisitOperatorDeclaration(OperatorDeclaration operatorDeclaration)
819
return VisitMethodMember(operatorDeclaration);
822
ResolveResult IAstVisitor<ResolveResult>.VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration)
824
return VisitMethodMember(constructorDeclaration);
827
ResolveResult IAstVisitor<ResolveResult>.VisitDestructorDeclaration(DestructorDeclaration destructorDeclaration)
829
return VisitMethodMember(destructorDeclaration);
832
// handle properties/indexers
833
ResolveResult VisitPropertyMember(EntityDeclaration propertyOrIndexerDeclaration)
835
CSharpResolver oldResolver = resolver;
838
if (parsedFile != null) {
839
member = GetMemberFromLocation(propertyOrIndexerDeclaration.StartLocation);
841
// Re-discover the property:
842
string name = propertyOrIndexerDeclaration.Name;
843
var parameterTypeReferences = TypeSystemConvertVisitor.GetParameterTypes(propertyOrIndexerDeclaration.GetChildrenByRole(Roles.Parameter));
844
AstType explicitInterfaceAstType = propertyOrIndexerDeclaration.GetChildByRole(EntityDeclaration.PrivateImplementationTypeRole);
845
ITypeReference explicitInterfaceType = null;
846
if (!explicitInterfaceAstType.IsNull) {
847
explicitInterfaceType = explicitInterfaceAstType.ToTypeReference();
849
member = AbstractUnresolvedMember.Resolve(
850
resolver.CurrentTypeResolveContext, propertyOrIndexerDeclaration.EntityType, name,
851
explicitInterfaceType, parameterTypeReferences: parameterTypeReferences);
853
resolver = resolver.WithCurrentMember(member);
855
for (AstNode node = propertyOrIndexerDeclaration.FirstChild; node != null; node = node.NextSibling) {
856
if (node.Role == PropertyDeclaration.SetterRole && member != null) {
857
resolver = resolver.PushBlock();
858
resolver = resolver.AddVariable(new DefaultParameter(member.ReturnType, "value"));
860
resolver = resolver.PopBlock();
866
return new MemberResolveResult(null, member, false);
870
resolver = oldResolver;
874
ResolveResult IAstVisitor<ResolveResult>.VisitPropertyDeclaration(PropertyDeclaration propertyDeclaration)
876
return VisitPropertyMember(propertyDeclaration);
879
ResolveResult IAstVisitor<ResolveResult>.VisitIndexerDeclaration(IndexerDeclaration indexerDeclaration)
881
return VisitPropertyMember(indexerDeclaration);
884
ResolveResult IAstVisitor<ResolveResult>.VisitCustomEventDeclaration(CustomEventDeclaration eventDeclaration)
886
CSharpResolver oldResolver = resolver;
889
if (parsedFile != null) {
890
member = GetMemberFromLocation(eventDeclaration.StartLocation);
892
string name = eventDeclaration.Name;
893
AstType explicitInterfaceAstType = eventDeclaration.PrivateImplementationType;
894
if (explicitInterfaceAstType.IsNull) {
895
member = AbstractUnresolvedMember.Resolve(resolver.CurrentTypeResolveContext, EntityType.Event, name);
897
member = AbstractUnresolvedMember.Resolve(resolver.CurrentTypeResolveContext, EntityType.Event, name,
898
explicitInterfaceAstType.ToTypeReference());
901
resolver = resolver.WithCurrentMember(member);
903
if (member != null) {
904
resolver = resolver.PushBlock();
905
resolver = resolver.AddVariable(new DefaultParameter(member.ReturnType, "value"));
906
ScanChildren(eventDeclaration);
908
ScanChildren(eventDeclaration);
912
return new MemberResolveResult(null, member, false);
916
resolver = oldResolver;
920
ResolveResult IAstVisitor<ResolveResult>.VisitParameterDeclaration(ParameterDeclaration parameterDeclaration)
922
ScanChildren(parameterDeclaration);
923
if (resolverEnabled) {
924
string name = parameterDeclaration.Name;
925
// Look in lambda parameters:
926
foreach (IParameter p in resolver.LocalVariables.OfType<IParameter>()) {
928
return new LocalResolveResult(p);
931
IParameterizedMember pm = resolver.CurrentMember as IParameterizedMember;
932
if (pm == null && resolver.CurrentTypeDefinition != null) {
933
// Also consider delegate parameters:
934
pm = resolver.CurrentTypeDefinition.GetDelegateInvokeMethod();
935
// pm will be null if the current type isn't a delegate
938
foreach (IParameter p in pm.Parameters) {
939
if (p.Name == name) {
940
return new LocalResolveResult(p);
951
ResolveResult IAstVisitor<ResolveResult>.VisitTypeParameterDeclaration(TypeParameterDeclaration typeParameterDeclaration)
953
ScanChildren(typeParameterDeclaration);
954
if (resolverEnabled) {
955
string name = typeParameterDeclaration.Name;
956
IMethod m = resolver.CurrentMember as IMethod;
958
foreach (var tp in m.TypeParameters) {
960
return new TypeResolveResult(tp);
963
if (resolver.CurrentTypeDefinition != null) {
964
var typeParameters = resolver.CurrentTypeDefinition.TypeParameters;
965
// look backwards so that TPs in the current type take precedence over those copied from outer types
966
for (int i = typeParameters.Count - 1; i >= 0; i--) {
967
if (typeParameters[i].Name == name)
968
return new TypeResolveResult(typeParameters[i]);
977
ResolveResult IAstVisitor<ResolveResult>.VisitEnumMemberDeclaration(EnumMemberDeclaration enumMemberDeclaration)
979
CSharpResolver oldResolver = resolver;
981
// Scan enum member attributes before setting resolver.CurrentMember, so that
982
// enum values used as attribute arguments have the correct type.
983
// (within an enum member, all other enum members are treated as having their underlying type)
984
foreach (var attributeSection in enumMemberDeclaration.Attributes)
985
Scan(attributeSection);
987
IMember member = null;
988
if (parsedFile != null) {
989
member = GetMemberFromLocation(enumMemberDeclaration.StartLocation);
990
} else if (resolver.CurrentTypeDefinition != null) {
991
string name = enumMemberDeclaration.Name;
992
member = resolver.CurrentTypeDefinition.GetFields(f => f.Name == name, GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault();
994
resolver = resolver.WithCurrentMember(member);
996
if (resolverEnabled && resolver.CurrentTypeDefinition != null) {
997
ResolveAndProcessConversion(enumMemberDeclaration.Initializer, resolver.CurrentTypeDefinition.EnumUnderlyingType);
998
if (resolverEnabled && member != null)
999
return new MemberResolveResult(null, member, false);
1003
Scan(enumMemberDeclaration.Initializer);
1007
resolver = oldResolver;
1012
#region Track CheckForOverflow
1013
ResolveResult IAstVisitor<ResolveResult>.VisitCheckedExpression(CheckedExpression checkedExpression)
1015
CSharpResolver oldResolver = resolver;
1017
resolver = resolver.WithCheckForOverflow(true);
1018
if (resolverEnabled) {
1019
return Resolve(checkedExpression.Expression);
1021
ScanChildren(checkedExpression);
1025
resolver = oldResolver;
1029
ResolveResult IAstVisitor<ResolveResult>.VisitUncheckedExpression(UncheckedExpression uncheckedExpression)
1031
CSharpResolver oldResolver = resolver;
1033
resolver = resolver.WithCheckForOverflow(false);
1034
if (resolverEnabled) {
1035
return Resolve(uncheckedExpression.Expression);
1037
ScanChildren(uncheckedExpression);
1041
resolver = oldResolver;
1045
ResolveResult IAstVisitor<ResolveResult>.VisitCheckedStatement(CheckedStatement checkedStatement)
1047
CSharpResolver oldResolver = resolver;
1049
resolver = resolver.WithCheckForOverflow(true);
1050
ScanChildren(checkedStatement);
1053
resolver = oldResolver;
1057
ResolveResult IAstVisitor<ResolveResult>.VisitUncheckedStatement(UncheckedStatement uncheckedStatement)
1059
CSharpResolver oldResolver = resolver;
1061
resolver = resolver.WithCheckForOverflow(false);
1062
ScanChildren(uncheckedStatement);
1065
resolver = oldResolver;
1070
#region Visit AnonymousTypeCreateExpression
1071
static string GetAnonymousTypePropertyName(Expression expr, out Expression resolveExpr)
1073
if (expr is NamedExpression) {
1074
var namedArgExpr = (NamedExpression)expr;
1075
resolveExpr = namedArgExpr.Expression;
1076
return namedArgExpr.Name;
1078
// no name given, so it's a projection initializer
1079
if (expr is MemberReferenceExpression) {
1081
return ((MemberReferenceExpression)expr).MemberName;
1083
if (expr is IdentifierExpression) {
1085
return ((IdentifierExpression)expr).Identifier;
1091
class AnonymousTypeMember
1093
public readonly Expression Expression;
1094
public readonly ResolveResult Initializer;
1096
public AnonymousTypeMember(Expression expression, ResolveResult initializer)
1098
this.Expression = expression;
1099
this.Initializer = initializer;
1103
ResolveResult IAstVisitor<ResolveResult>.VisitAnonymousTypeCreateExpression(AnonymousTypeCreateExpression anonymousTypeCreateExpression)
1105
// 7.6.10.6 Anonymous object creation expressions
1106
List<IUnresolvedProperty> unresolvedProperties = new List<IUnresolvedProperty>();
1107
List<AnonymousTypeMember> members = new List<AnonymousTypeMember>();
1108
foreach (var expr in anonymousTypeCreateExpression.Initializers) {
1109
Expression resolveExpr;
1110
var name = GetAnonymousTypePropertyName(expr, out resolveExpr);
1111
if (resolveExpr != null) {
1112
var initRR = Resolve(resolveExpr);
1113
var returnTypeRef = initRR.Type.ToTypeReference();
1114
var property = new DefaultUnresolvedProperty {
1116
Accessibility = Accessibility.Public,
1117
ReturnType = returnTypeRef,
1118
Getter = new DefaultUnresolvedMethod {
1119
Name = "get_" + name,
1120
Accessibility = Accessibility.Public,
1121
ReturnType = returnTypeRef
1124
unresolvedProperties.Add(property);
1125
members.Add(new AnonymousTypeMember(expr, initRR));
1130
var anonymousType = new AnonymousType(resolver.Compilation, unresolvedProperties);
1131
var properties = anonymousType.GetProperties().ToList();
1132
Debug.Assert(properties.Count == members.Count);
1133
List<ResolveResult> assignments = new List<ResolveResult>();
1134
for (int i = 0; i < members.Count; i++) {
1135
ResolveResult lhs = new MemberResolveResult(new InitializedObjectResolveResult(anonymousType), properties[i]);
1136
ResolveResult rhs = members[i].Initializer;
1137
ResolveResult assignment = resolver.ResolveAssignment(AssignmentOperatorType.Assign, lhs, rhs);
1138
var ne = members[i].Expression as NamedExpression;
1140
StoreCurrentState(ne);
1141
// ne.Expression was already resolved by the first loop
1142
StoreResult(ne, lhs);
1144
assignments.Add(assignment);
1146
var anonymousCtor = DefaultResolvedMethod.GetDummyConstructor(resolver.Compilation, anonymousType);
1147
return new InvocationResolveResult(null, anonymousCtor, initializerStatements: assignments);
1151
#region Visit Expressions
1152
ResolveResult IAstVisitor<ResolveResult>.VisitArrayCreateExpression(ArrayCreateExpression arrayCreateExpression)
1154
int dimensions = arrayCreateExpression.Arguments.Count;
1155
ResolveResult[] sizeArguments;
1156
IEnumerable<ArraySpecifier> additionalArraySpecifiers;
1157
if (dimensions == 0) {
1158
var firstSpecifier = arrayCreateExpression.AdditionalArraySpecifiers.FirstOrDefault();
1159
if (firstSpecifier != null) {
1160
dimensions = firstSpecifier.Dimensions;
1161
additionalArraySpecifiers = arrayCreateExpression.AdditionalArraySpecifiers.Skip(1);
1164
additionalArraySpecifiers = arrayCreateExpression.AdditionalArraySpecifiers;
1166
sizeArguments = null;
1168
sizeArguments = new ResolveResult[dimensions];
1170
foreach (var node in arrayCreateExpression.Arguments)
1171
sizeArguments[pos++] = Resolve(node);
1172
additionalArraySpecifiers = arrayCreateExpression.AdditionalArraySpecifiers;
1175
List<Expression> initializerElements;
1176
ResolveResult[] initializerElementResults;
1177
if (arrayCreateExpression.Initializer.IsNull) {
1178
initializerElements = null;
1179
initializerElementResults = null;
1181
StoreCurrentState(arrayCreateExpression.Initializer);
1183
initializerElements = new List<Expression>();
1184
UnpackArrayInitializer(initializerElements, arrayCreateExpression.Initializer, dimensions, true);
1185
initializerElementResults = new ResolveResult[initializerElements.Count];
1186
for (int i = 0; i < initializerElementResults.Length; i++) {
1187
initializerElementResults[i] = Resolve(initializerElements[i]);
1189
StoreResult(arrayCreateExpression.Initializer, voidResult);
1192
ArrayCreateResolveResult acrr;
1193
if (arrayCreateExpression.Type.IsNull) {
1194
acrr = resolver.ResolveArrayCreation(null, dimensions, sizeArguments, initializerElementResults);
1196
IType elementType = ResolveType(arrayCreateExpression.Type);
1197
foreach (var spec in additionalArraySpecifiers.Reverse()) {
1198
elementType = new ArrayType(resolver.Compilation, elementType, spec.Dimensions);
1200
acrr = resolver.ResolveArrayCreation(elementType, dimensions, sizeArguments, initializerElementResults);
1205
void UnpackArrayInitializer(List<Expression> elementList, ArrayInitializerExpression initializer, int dimensions, bool resolveNestedInitializesToVoid)
1207
Debug.Assert(dimensions >= 1);
1208
if (dimensions > 1) {
1209
foreach (var node in initializer.Elements) {
1210
ArrayInitializerExpression aie = node as ArrayInitializerExpression;
1212
if (resolveNestedInitializesToVoid) {
1213
StoreCurrentState(aie);
1214
StoreResult(aie, voidResult);
1216
UnpackArrayInitializer(elementList, aie, dimensions - 1, resolveNestedInitializesToVoid);
1218
elementList.Add(node);
1222
foreach (var expr in initializer.Elements)
1223
elementList.Add(expr);
1227
ResolveResult IAstVisitor<ResolveResult>.VisitArrayInitializerExpression(ArrayInitializerExpression arrayInitializerExpression)
1229
// Array initializers are handled by their parent expression.
1230
ScanChildren(arrayInitializerExpression);
1234
ResolveResult IAstVisitor<ResolveResult>.VisitAsExpression(AsExpression asExpression)
1236
if (resolverEnabled) {
1237
ResolveResult input = Resolve(asExpression.Expression);
1238
var targetType = ResolveType(asExpression.Type);
1239
return new ConversionResolveResult(targetType, input, Conversion.TryCast);
1241
ScanChildren(asExpression);
1246
ResolveResult IAstVisitor<ResolveResult>.VisitAssignmentExpression(AssignmentExpression assignmentExpression)
1248
if (resolverEnabled) {
1249
Expression left = assignmentExpression.Left;
1250
Expression right = assignmentExpression.Right;
1251
ResolveResult leftResult = Resolve(left);
1252
ResolveResult rightResult = Resolve(right);
1253
ResolveResult rr = resolver.ResolveAssignment(assignmentExpression.Operator, leftResult, rightResult);
1254
ProcessConversionsInBinaryOperatorResult(left, right, rr);
1257
ScanChildren(assignmentExpression);
1262
ResolveResult IAstVisitor<ResolveResult>.VisitBaseReferenceExpression(BaseReferenceExpression baseReferenceExpression)
1264
if (resolverEnabled) {
1265
return resolver.ResolveBaseReference();
1267
ScanChildren(baseReferenceExpression);
1272
ResolveResult IAstVisitor<ResolveResult>.VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression)
1274
if (resolverEnabled) {
1275
Expression left = binaryOperatorExpression.Left;
1276
Expression right = binaryOperatorExpression.Right;
1277
ResolveResult leftResult = Resolve(left);
1278
ResolveResult rightResult = Resolve(right);
1279
ResolveResult rr = resolver.ResolveBinaryOperator(binaryOperatorExpression.Operator, leftResult, rightResult);
1280
ProcessConversionsInBinaryOperatorResult(left, right, rr);
1283
ScanChildren(binaryOperatorExpression);
1288
ResolveResult ProcessConversionsInBinaryOperatorResult(Expression left, Expression right, ResolveResult rr)
1290
OperatorResolveResult orr = rr as OperatorResolveResult;
1291
if (orr != null && orr.Operands.Count == 2) {
1292
ProcessConversionResult(left, orr.Operands[0] as ConversionResolveResult);
1293
ProcessConversionResult(right, orr.Operands[1] as ConversionResolveResult);
1295
InvocationResolveResult irr = rr as InvocationResolveResult;
1296
if (irr != null && irr.Arguments.Count == 2) {
1297
ProcessConversionResult(left, irr.Arguments[0] as ConversionResolveResult);
1298
ProcessConversionResult(right, irr.Arguments[1] as ConversionResolveResult);
1304
ResolveResult IAstVisitor<ResolveResult>.VisitCastExpression(CastExpression castExpression)
1306
if (resolverEnabled) {
1307
IType targetType = ResolveType(castExpression.Type);
1308
Expression expr = castExpression.Expression;
1309
ResolveResult rr = resolver.ResolveCast(targetType, Resolve(expr));
1310
ProcessConversionResult(expr, rr as ConversionResolveResult);
1313
ScanChildren(castExpression);
1318
ResolveResult IAstVisitor<ResolveResult>.VisitConditionalExpression(ConditionalExpression conditionalExpression)
1320
if (resolverEnabled) {
1321
Expression condition = conditionalExpression.Condition;
1322
Expression trueExpr = conditionalExpression.TrueExpression;
1323
Expression falseExpr = conditionalExpression.FalseExpression;
1325
ResolveResult rr = resolver.ResolveConditional(Resolve(condition), Resolve(trueExpr), Resolve(falseExpr));
1326
OperatorResolveResult corr = rr as OperatorResolveResult;
1327
if (corr != null && corr.Operands.Count == 3) {
1328
ProcessConversionResult(condition, corr.Operands[0] as ConversionResolveResult);
1329
ProcessConversionResult(trueExpr, corr.Operands[1] as ConversionResolveResult);
1330
ProcessConversionResult(falseExpr, corr.Operands[2] as ConversionResolveResult);
1334
ScanChildren(conditionalExpression);
1339
ResolveResult IAstVisitor<ResolveResult>.VisitDefaultValueExpression(DefaultValueExpression defaultValueExpression)
1341
if (resolverEnabled) {
1342
return resolver.ResolveDefaultValue(ResolveType(defaultValueExpression.Type));
1344
ScanChildren(defaultValueExpression);
1349
ResolveResult IAstVisitor<ResolveResult>.VisitDirectionExpression(DirectionExpression directionExpression)
1351
if (resolverEnabled) {
1352
ResolveResult rr = Resolve(directionExpression.Expression);
1353
return new ByReferenceResolveResult(rr, directionExpression.FieldDirection == FieldDirection.Out);
1355
ScanChildren(directionExpression);
1360
ResolveResult IAstVisitor<ResolveResult>.VisitEmptyExpression(EmptyExpression emptyExpression)
1365
ResolveResult IAstVisitor<ResolveResult>.VisitIndexerExpression(IndexerExpression indexerExpression)
1367
if (resolverEnabled) {
1368
Expression target = indexerExpression.Target;
1369
ResolveResult targetResult = Resolve(target);
1370
string[] argumentNames;
1371
ResolveResult[] arguments = GetArguments(indexerExpression.Arguments, out argumentNames);
1372
ResolveResult rr = resolver.ResolveIndexer(targetResult, arguments, argumentNames);
1373
ArrayAccessResolveResult aarr = rr as ArrayAccessResolveResult;
1375
ProcessConversionResults(indexerExpression.Arguments, aarr.Indexes);
1377
ProcessConversionsInInvocation(target, indexerExpression.Arguments, rr as CSharpInvocationResolveResult);
1381
ScanChildren(indexerExpression);
1386
ResolveResult IAstVisitor<ResolveResult>.VisitIsExpression(IsExpression isExpression)
1388
if (resolverEnabled) {
1389
ResolveResult input = Resolve(isExpression.Expression);
1390
IType targetType = ResolveType(isExpression.Type);
1391
IType booleanType = resolver.Compilation.FindType(KnownTypeCode.Boolean);
1392
return new TypeIsResolveResult(input, targetType, booleanType);
1394
ScanChildren(isExpression);
1399
// NamedArgumentExpression is "identifier: Expression"
1400
ResolveResult IAstVisitor<ResolveResult>.VisitNamedArgumentExpression(NamedArgumentExpression namedArgumentExpression)
1402
// The parent expression takes care of handling NamedArgumentExpressions
1403
// by calling GetArguments().
1404
// This method gets called only when scanning, or when the named argument is used
1405
// in an invalid context.
1406
Scan(namedArgumentExpression.Expression);
1410
// NamedExpression is "identifier = Expression" in object initializers and attributes
1411
ResolveResult IAstVisitor<ResolveResult>.VisitNamedExpression(NamedExpression namedExpression)
1413
// The parent expression takes care of handling NamedExpression
1414
// by calling HandleObjectInitializer() or HandleNamedExpression().
1415
// This method gets called only when scanning, or when the named expression is used
1416
// in an invalid context.
1417
ScanChildren(namedExpression);
1421
void HandleNamedExpression(NamedExpression namedExpression, List<ResolveResult> initializerStatements)
1423
StoreCurrentState(namedExpression);
1424
Expression rhs = namedExpression.Expression;
1425
ResolveResult lhsRR = resolver.ResolveIdentifierInObjectInitializer(namedExpression.Name);
1426
if (rhs is ArrayInitializerExpression) {
1427
HandleObjectInitializer(lhsRR, (ArrayInitializerExpression)rhs, initializerStatements);
1429
var rhsRR = Resolve(rhs);
1430
var rr = resolver.ResolveAssignment(AssignmentOperatorType.Assign, lhsRR, rhsRR) as OperatorResolveResult;
1432
ProcessConversionResult(rhs, rr.Operands[1] as ConversionResolveResult);
1433
initializerStatements.Add(rr);
1436
StoreResult(namedExpression, lhsRR);
1439
ResolveResult IAstVisitor<ResolveResult>.VisitNullReferenceExpression(NullReferenceExpression nullReferenceExpression)
1441
return resolver.ResolvePrimitive(null);
1444
ResolveResult IAstVisitor<ResolveResult>.VisitObjectCreateExpression(ObjectCreateExpression objectCreateExpression)
1446
if (resolverEnabled || !objectCreateExpression.Initializer.IsNull) {
1447
var typeResolveResult = Resolve(objectCreateExpression.Type);
1448
if (typeResolveResult.IsError) {
1449
ScanChildren (objectCreateExpression);
1450
return typeResolveResult;
1452
IType type = typeResolveResult.Type;
1454
List<ResolveResult> initializerStatements = null;
1455
var initializer = objectCreateExpression.Initializer;
1456
if (!initializer.IsNull) {
1457
initializerStatements = new List<ResolveResult>();
1458
HandleObjectInitializer(new InitializedObjectResolveResult(type), initializer, initializerStatements);
1461
string[] argumentNames;
1462
ResolveResult[] arguments = GetArguments(objectCreateExpression.Arguments, out argumentNames);
1464
ResolveResult rr = resolver.ResolveObjectCreation(type, arguments, argumentNames, false, initializerStatements);
1465
if (arguments.Length == 1 && rr.Type.Kind == TypeKind.Delegate) {
1466
// process conversion in case it's a delegate creation
1467
ProcessConversionResult(objectCreateExpression.Arguments.Single(), rr as ConversionResolveResult);
1468
// wrap the result so that the delegate creation is not handled as a reference
1469
// to the target method - otherwise FindReferencedEntities would produce two results for
1470
// the same delegate creation.
1471
return WrapResult(rr);
1473
// process conversions in all other cases
1474
ProcessConversionsInInvocation(null, objectCreateExpression.Arguments, rr as CSharpInvocationResolveResult);
1478
ScanChildren(objectCreateExpression);
1483
void HandleObjectInitializer(ResolveResult initializedObject, ArrayInitializerExpression initializer, List<ResolveResult> initializerStatements)
1485
StoreCurrentState(initializer);
1486
resolver = resolver.PushObjectInitializer(initializedObject);
1487
foreach (Expression element in initializer.Elements) {
1488
ArrayInitializerExpression aie = element as ArrayInitializerExpression;
1490
StoreCurrentState(aie);
1491
// constructor argument list in collection initializer
1492
ResolveResult[] addArguments = new ResolveResult[aie.Elements.Count];
1494
foreach (var addArgument in aie.Elements) {
1495
addArguments[i++] = Resolve(addArgument);
1497
MemberLookup memberLookup = resolver.CreateMemberLookup();
1498
var addRR = memberLookup.Lookup(initializedObject, "Add", EmptyList<IType>.Instance, true);
1499
var mgrr = addRR as MethodGroupResolveResult;
1501
OverloadResolution or = mgrr.PerformOverloadResolution(resolver.Compilation, addArguments, null, false, false, resolver.conversions);
1502
var invocationRR = or.CreateResolveResult(initializedObject);
1503
StoreResult(aie, invocationRR);
1504
ProcessConversionsInInvocation(null, aie.Elements, invocationRR);
1505
initializerStatements.Add(invocationRR);
1507
StoreResult(aie, addRR);
1509
} else if (element is NamedExpression) {
1510
HandleNamedExpression((NamedExpression)element, initializerStatements);
1512
// unknown kind of expression
1516
resolver = resolver.PopObjectInitializer();
1517
StoreResult(initializer, voidResult);
1520
ResolveResult IAstVisitor<ResolveResult>.VisitParenthesizedExpression(ParenthesizedExpression parenthesizedExpression)
1522
if (resolverEnabled) {
1523
return Resolve(parenthesizedExpression.Expression);
1525
Scan(parenthesizedExpression.Expression);
1530
ResolveResult IAstVisitor<ResolveResult>.VisitPointerReferenceExpression(PointerReferenceExpression pointerReferenceExpression)
1532
if (resolverEnabled) {
1533
ResolveResult target = Resolve(pointerReferenceExpression.Target);
1534
ResolveResult deferencedTarget = resolver.ResolveUnaryOperator(UnaryOperatorType.Dereference, target);
1535
List<IType> typeArguments = new List<IType>();
1536
foreach (AstType typeArgument in pointerReferenceExpression.TypeArguments) {
1537
typeArguments.Add(ResolveType(typeArgument));
1539
return resolver.ResolveMemberAccess(deferencedTarget, pointerReferenceExpression.MemberName,
1541
GetNameLookupMode(pointerReferenceExpression));
1543
ScanChildren(pointerReferenceExpression);
1548
ResolveResult IAstVisitor<ResolveResult>.VisitPrimitiveExpression(PrimitiveExpression primitiveExpression)
1550
return resolver.ResolvePrimitive(primitiveExpression.Value);
1553
ResolveResult IAstVisitor<ResolveResult>.VisitSizeOfExpression(SizeOfExpression sizeOfExpression)
1555
return resolver.ResolveSizeOf(ResolveType(sizeOfExpression.Type));
1558
ResolveResult IAstVisitor<ResolveResult>.VisitStackAllocExpression(StackAllocExpression stackAllocExpression)
1560
ResolveAndProcessConversion(stackAllocExpression.CountExpression, resolver.Compilation.FindType(KnownTypeCode.Int32));
1561
return new ResolveResult(new PointerType(ResolveType(stackAllocExpression.Type)));
1564
ResolveResult IAstVisitor<ResolveResult>.VisitThisReferenceExpression(ThisReferenceExpression thisReferenceExpression)
1566
return resolver.ResolveThisReference();
1569
ResolveResult IAstVisitor<ResolveResult>.VisitTypeOfExpression(TypeOfExpression typeOfExpression)
1571
if (resolverEnabled) {
1572
return resolver.ResolveTypeOf(ResolveType(typeOfExpression.Type));
1574
Scan(typeOfExpression.Type);
1579
ResolveResult IAstVisitor<ResolveResult>.VisitTypeReferenceExpression(TypeReferenceExpression typeReferenceExpression)
1581
if (resolverEnabled) {
1582
return Resolve(typeReferenceExpression.Type);
1584
Scan(typeReferenceExpression.Type);
1589
ResolveResult IAstVisitor<ResolveResult>.VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression)
1591
if (resolverEnabled) {
1592
Expression expr = unaryOperatorExpression.Expression;
1593
ResolveResult input = Resolve(expr);
1594
ITypeDefinition inputTypeDef = input.Type.GetDefinition();
1595
if (input.IsCompileTimeConstant && expr is PrimitiveExpression && inputTypeDef != null) {
1596
// Special cases for int.MinValue and long.MinValue
1597
if (inputTypeDef.KnownTypeCode == KnownTypeCode.UInt32 && 2147483648.Equals(input.ConstantValue)) {
1598
return new ConstantResolveResult(resolver.Compilation.FindType(KnownTypeCode.Int32), -2147483648);
1599
} else if (inputTypeDef.KnownTypeCode == KnownTypeCode.UInt64 && 9223372036854775808.Equals(input.ConstantValue)) {
1600
return new ConstantResolveResult(resolver.Compilation.FindType(KnownTypeCode.Int64), -9223372036854775808);
1603
ResolveResult rr = resolver.ResolveUnaryOperator(unaryOperatorExpression.Operator, input);
1604
OperatorResolveResult uorr = rr as OperatorResolveResult;
1605
if (uorr != null && uorr.Operands.Count == 1) {
1606
ProcessConversionResult(expr, uorr.Operands[0] as ConversionResolveResult);
1608
InvocationResolveResult irr = rr as InvocationResolveResult;
1609
if (irr != null && irr.Arguments.Count == 1) {
1610
ProcessConversionResult(expr, irr.Arguments[0] as ConversionResolveResult);
1615
ScanChildren(unaryOperatorExpression);
1620
ResolveResult IAstVisitor<ResolveResult>.VisitUndocumentedExpression(UndocumentedExpression undocumentedExpression)
1622
ScanChildren(undocumentedExpression);
1624
switch (undocumentedExpression.UndocumentedExpressionType) {
1625
case UndocumentedExpressionType.ArgListAccess:
1626
case UndocumentedExpressionType.ArgList:
1627
resultType = resolver.Compilation.FindType(typeof(RuntimeArgumentHandle));
1629
case UndocumentedExpressionType.RefValue:
1630
var tre = undocumentedExpression.Arguments.ElementAtOrDefault(1) as TypeReferenceExpression;
1632
resultType = ResolveType(tre.Type);
1634
resultType = SpecialType.UnknownType;
1636
case UndocumentedExpressionType.RefType:
1637
resultType = resolver.Compilation.FindType(KnownTypeCode.Type);
1639
case UndocumentedExpressionType.MakeRef:
1640
resultType = resolver.Compilation.FindType(typeof(TypedReference));
1643
throw new InvalidOperationException("Invalid value for UndocumentedExpressionType");
1645
return new ResolveResult(resultType);
1649
#region Visit Identifier/MemberReference/Invocation-Expression
1650
// IdentifierExpression, MemberReferenceExpression and InvocationExpression
1651
// are grouped together because they have to work together for
1652
// "7.6.4.1 Identical simple names and type names" support
1653
List<IType> ResolveTypeArguments(IEnumerable<AstType> typeArguments)
1655
List<IType> result = new List<IType>();
1656
foreach (AstType typeArgument in typeArguments) {
1657
result.Add(ResolveType(typeArgument));
1662
ResolveResult[] GetArguments(IEnumerable<Expression> argumentExpressions, out string[] argumentNames)
1664
argumentNames = null;
1665
ResolveResult[] arguments = new ResolveResult[argumentExpressions.Count()];
1667
foreach (AstNode argument in argumentExpressions) {
1668
NamedArgumentExpression nae = argument as NamedArgumentExpression;
1669
AstNode argumentValue;
1671
if (argumentNames == null)
1672
argumentNames = new string[arguments.Length];
1673
argumentNames[i] = nae.Name;
1674
argumentValue = nae.Expression;
1676
argumentValue = argument;
1678
arguments[i++] = Resolve(argumentValue);
1683
static NameLookupMode GetNameLookupMode(Expression expr)
1685
InvocationExpression ie = expr.Parent as InvocationExpression;
1686
if (ie != null && ie.Target == expr)
1687
return NameLookupMode.InvocationTarget;
1689
return NameLookupMode.Expression;
1693
/// Gets whether 'rr' is considered a static access on the target identifier.
1695
/// <param name="rr">Resolve Result of the MemberReferenceExpression</param>
1696
/// <param name="invocationRR">Resolve Result of the InvocationExpression</param>
1697
bool IsStaticResult(ResolveResult rr, ResolveResult invocationRR)
1699
if (rr is TypeResolveResult)
1701
MemberResolveResult mrr = (rr is MethodGroupResolveResult ? invocationRR : rr) as MemberResolveResult;
1702
return mrr != null && mrr.Member.IsStatic;
1705
ResolveResult IAstVisitor<ResolveResult>.VisitIdentifierExpression(IdentifierExpression identifierExpression)
1707
// Note: this method is not called when it occurs in a situation where an ambiguity between
1708
// simple names and type names might occur.
1709
if (resolverEnabled) {
1710
var typeArguments = ResolveTypeArguments(identifierExpression.TypeArguments);
1711
var lookupMode = GetNameLookupMode(identifierExpression);
1712
return resolver.LookupSimpleNameOrTypeName(
1713
identifierExpression.Identifier, typeArguments, lookupMode);
1715
ScanChildren(identifierExpression);
1720
ResolveResult IAstVisitor<ResolveResult>.VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression)
1722
// target = Resolve(identifierExpression = memberReferenceExpression.Target)
1723
// trr = ResolveType(identifierExpression)
1724
// rr = Resolve(memberReferenceExpression)
1726
IdentifierExpression identifierExpression = memberReferenceExpression.Target as IdentifierExpression;
1727
if (identifierExpression != null && identifierExpression.TypeArguments.Count == 0) {
1728
// Special handling for Ā§7.6.4.1 Identicial simple names and type names
1729
StoreCurrentState(identifierExpression);
1730
ResolveResult target = resolver.ResolveSimpleName(identifierExpression.Identifier, EmptyList<IType>.Instance);
1731
TypeResolveResult trr;
1732
if (resolver.IsVariableReferenceWithSameType(target, identifierExpression.Identifier, out trr)) {
1734
ResolveResult rr = ResolveMemberReferenceOnGivenTarget(target, memberReferenceExpression);
1735
ResolveResult simpleNameRR = IsStaticResult(rr, null) ? trr : target;
1736
Log.WriteLine("Ambiguous simple name '{0}' was resolved to {1}", identifierExpression, simpleNameRR);
1737
StoreResult(identifierExpression, simpleNameRR);
1740
// It's not ambiguous
1741
Log.WriteLine("Simple name '{0}' was resolved to {1}", identifierExpression, target);
1742
StoreResult(identifierExpression, target);
1743
return ResolveMemberReferenceOnGivenTarget(target, memberReferenceExpression);
1746
// Regular code path
1747
if (resolverEnabled) {
1748
ResolveResult target = Resolve(memberReferenceExpression.Target);
1749
return ResolveMemberReferenceOnGivenTarget(target, memberReferenceExpression);
1751
ScanChildren(memberReferenceExpression);
1757
ResolveResult ResolveMemberReferenceOnGivenTarget(ResolveResult target, MemberReferenceExpression memberReferenceExpression)
1759
var typeArguments = ResolveTypeArguments(memberReferenceExpression.TypeArguments);
1760
return resolver.ResolveMemberAccess(
1761
target, memberReferenceExpression.MemberName, typeArguments,
1762
GetNameLookupMode(memberReferenceExpression));
1765
ResolveResult IAstVisitor<ResolveResult>.VisitInvocationExpression(InvocationExpression invocationExpression)
1767
// rr = Resolve(invocationExpression)
1768
// target = Resolve(memberReferenceExpression = invocationExpression.Target)
1769
// idRR = Resolve(identifierExpression = memberReferenceExpression.Target)
1770
// trr = ResolveType(identifierExpression)
1772
MemberReferenceExpression mre = invocationExpression.Target as MemberReferenceExpression;
1773
IdentifierExpression identifierExpression = mre != null ? mre.Target as IdentifierExpression : null;
1774
if (identifierExpression != null && identifierExpression.TypeArguments.Count == 0) {
1775
// Special handling for Ā§7.6.4.1 Identicial simple names and type names
1777
StoreCurrentState(identifierExpression);
1778
StoreCurrentState(mre);
1780
ResolveResult idRR = resolver.ResolveSimpleName(identifierExpression.Identifier, EmptyList<IType>.Instance);
1781
ResolveResult target = ResolveMemberReferenceOnGivenTarget(idRR, mre);
1782
Log.WriteLine("Member reference '{0}' on potentially-ambiguous simple-name was resolved to {1}", mre, target);
1783
StoreResult(mre, target);
1784
TypeResolveResult trr;
1785
if (resolver.IsVariableReferenceWithSameType(idRR, identifierExpression.Identifier, out trr)) {
1787
ResolveResult rr = ResolveInvocationOnGivenTarget(target, invocationExpression);
1788
ResolveResult simpleNameRR = IsStaticResult(target, rr) ? trr : idRR;
1789
Log.WriteLine("Ambiguous simple name '{0}' was resolved to {1}",
1790
identifierExpression, simpleNameRR);
1791
StoreResult(identifierExpression, simpleNameRR);
1794
// It's not ambiguous
1795
Log.WriteLine("Simple name '{0}' was resolved to {1}", identifierExpression, idRR);
1796
StoreResult(identifierExpression, idRR);
1797
return ResolveInvocationOnGivenTarget(target, invocationExpression);
1800
// Regular code path
1801
if (resolverEnabled) {
1802
ResolveResult target = Resolve(invocationExpression.Target);
1803
return ResolveInvocationOnGivenTarget(target, invocationExpression);
1805
ScanChildren(invocationExpression);
1811
ResolveResult ResolveInvocationOnGivenTarget(ResolveResult target, InvocationExpression invocationExpression)
1813
string[] argumentNames;
1814
ResolveResult[] arguments = GetArguments(invocationExpression.Arguments, out argumentNames);
1815
ResolveResult rr = resolver.ResolveInvocation(target, arguments, argumentNames);
1816
ProcessConversionsInInvocation(invocationExpression.Target, invocationExpression.Arguments, rr as CSharpInvocationResolveResult);
1821
#region Lamdbas / Anonymous Functions
1822
ResolveResult IAstVisitor<ResolveResult>.VisitAnonymousMethodExpression(AnonymousMethodExpression anonymousMethodExpression)
1824
return HandleExplicitlyTypedLambda(
1825
anonymousMethodExpression.Parameters, anonymousMethodExpression.Body,
1826
isAnonymousMethod: true,
1827
hasParameterList: anonymousMethodExpression.HasParameterList,
1828
isAsync: anonymousMethodExpression.IsAsync);
1831
ResolveResult IAstVisitor<ResolveResult>.VisitLambdaExpression(LambdaExpression lambdaExpression)
1833
bool isExplicitlyTyped = false;
1834
bool isImplicitlyTyped = false;
1835
foreach (var p in lambdaExpression.Parameters) {
1836
isImplicitlyTyped |= p.Type.IsNull;
1837
isExplicitlyTyped |= !p.Type.IsNull;
1839
if (isExplicitlyTyped || !isImplicitlyTyped) {
1840
return HandleExplicitlyTypedLambda(
1841
lambdaExpression.Parameters, lambdaExpression.Body,
1842
isAnonymousMethod: false, hasParameterList: true, isAsync: lambdaExpression.IsAsync);
1844
return new ImplicitlyTypedLambda(lambdaExpression, this);
1848
#region Explicitly typed
1849
ExplicitlyTypedLambda HandleExplicitlyTypedLambda(
1850
AstNodeCollection<ParameterDeclaration> parameterDeclarations,
1851
AstNode body, bool isAnonymousMethod, bool hasParameterList, bool isAsync)
1853
CSharpResolver oldResolver = resolver;
1854
List<IParameter> parameters = (hasParameterList || parameterDeclarations.Any()) ? new List<IParameter>() : null;
1855
//bool oldIsWithinLambdaExpression = resolver.IsWithinLambdaExpression;
1856
resolver = resolver.WithIsWithinLambdaExpression(true);
1857
foreach (var pd in parameterDeclarations) {
1858
IType type = ResolveType(pd.Type);
1859
if (pd.ParameterModifier == ParameterModifier.Ref || pd.ParameterModifier == ParameterModifier.Out)
1860
type = new ByReferenceType(type);
1862
IParameter p = new DefaultParameter(type, pd.Name, MakeRegion(pd),
1863
isRef: pd.ParameterModifier == ParameterModifier.Ref,
1864
isOut: pd.ParameterModifier == ParameterModifier.Out);
1865
// The parameter declaration must be scanned in the current context (without the new parameter)
1866
// in order to be consistent with the context in which we resolved pd.Type.
1867
StoreCurrentState(pd);
1868
StoreResult(pd, new LocalResolveResult(p));
1871
resolver = resolver.AddVariable(p);
1875
var lambda = new ExplicitlyTypedLambda(parameters, isAnonymousMethod, isAsync, resolver, this, body);
1877
// Don't scan the lambda body here - we'll do that later when analyzing the ExplicitlyTypedLambda.
1879
resolver = oldResolver;
1883
DomRegion MakeRegion(AstNode node)
1885
if (parsedFile != null)
1886
return new DomRegion(parsedFile.FileName, node.StartLocation, node.EndLocation);
1888
return node.GetRegion();
1891
sealed class ExplicitlyTypedLambda : LambdaBase
1893
readonly IList<IParameter> parameters;
1894
readonly bool isAnonymousMethod;
1895
readonly bool isAsync;
1897
CSharpResolver storedContext;
1898
ResolveVisitor visitor;
1901
IType inferredReturnType;
1902
IList<Expression> returnExpressions;
1903
IList<ResolveResult> returnValues;
1904
bool isValidAsVoidMethod;
1905
bool isEndpointUnreachable;
1907
// The actual return type is set when the lambda is applied by the conversion.
1908
IType actualReturnType;
1910
internal override bool IsUndecided {
1911
get { return actualReturnType == null; }
1914
internal override AstNode LambdaExpression {
1915
get { return body.Parent; }
1918
internal override AstNode BodyExpression {
1919
get { return body; }
1922
public override ResolveResult Body {
1924
if (body is Expression) {
1926
if (returnValues.Count == 1)
1927
return returnValues[0];
1929
return visitor.voidResult;
1933
public ExplicitlyTypedLambda(IList<IParameter> parameters, bool isAnonymousMethod, bool isAsync, CSharpResolver storedContext, ResolveVisitor visitor, AstNode body)
1935
this.parameters = parameters;
1936
this.isAnonymousMethod = isAnonymousMethod;
1937
this.isAsync = isAsync;
1938
this.storedContext = storedContext;
1939
this.visitor = visitor;
1942
if (visitor.undecidedLambdas == null)
1943
visitor.undecidedLambdas = new List<LambdaBase>();
1944
visitor.undecidedLambdas.Add(this);
1945
Log.WriteLine("Added undecided explicitly-typed lambda: " + this.LambdaExpression);
1948
public override IList<IParameter> Parameters {
1950
return parameters ?? EmptyList<IParameter>.Instance;
1956
// If it's not already analyzed
1957
if (inferredReturnType == null) {
1958
Log.WriteLine("Analyzing " + this.LambdaExpression + "...");
1961
visitor.ResetContext(
1964
var oldNavigator = visitor.navigator;
1965
visitor.navigator = new ConstantModeResolveVisitorNavigator(ResolveVisitorNavigationMode.Resolve, oldNavigator);
1966
visitor.AnalyzeLambda(body, isAsync, out isValidAsVoidMethod, out isEndpointUnreachable, out inferredReturnType, out returnExpressions, out returnValues);
1967
visitor.navigator = oldNavigator;
1970
Log.WriteLine("Finished analyzing " + this.LambdaExpression);
1972
if (inferredReturnType == null)
1973
throw new InvalidOperationException("AnalyzeLambda() didn't set inferredReturnType");
1978
public override Conversion IsValid(IType[] parameterTypes, IType returnType, CSharpConversions conversions)
1980
Log.WriteLine("Testing validity of {0} for return-type {1}...", this, returnType);
1982
bool valid = Analyze() && IsValidLambda(isValidAsVoidMethod, isEndpointUnreachable, isAsync, returnValues, returnType, conversions);
1984
Log.WriteLine("{0} is {1} for return-type {2}", this, valid ? "valid" : "invalid", returnType);
1985
return new AnonymousFunctionConversion(returnType, this, valid);
1988
public override IType GetInferredReturnType(IType[] parameterTypes)
1991
return inferredReturnType;
1994
public override bool IsImplicitlyTyped {
1995
get { return false; }
1998
public override bool IsAsync {
1999
get { return isAsync; }
2002
public override bool IsAnonymousMethod {
2003
get { return isAnonymousMethod; }
2006
public override bool HasParameterList {
2007
get { return parameters != null; }
2010
public override string ToString()
2012
return "[ExplicitlyTypedLambda " + this.LambdaExpression + "]";
2015
public void ApplyReturnType(ResolveVisitor parentVisitor, IType returnType)
2017
if (returnType == null)
2018
throw new ArgumentNullException("returnType");
2019
if (parentVisitor != visitor) {
2020
// Explicitly typed lambdas do not use a nested visitor
2021
throw new InvalidOperationException();
2023
if (actualReturnType != null) {
2024
if (actualReturnType.Equals(returnType))
2025
return; // return type already set
2026
throw new InvalidOperationException("inconsistent return types for explicitly-typed lambda");
2028
actualReturnType = returnType;
2029
visitor.undecidedLambdas.Remove(this);
2031
Log.WriteLine("Applying return type {0} to explicitly-typed lambda {1}", returnType, this.LambdaExpression);
2033
returnType = parentVisitor.UnpackTask(returnType);
2034
if (returnType.Kind != TypeKind.Void) {
2035
for (int i = 0; i < returnExpressions.Count; i++) {
2036
visitor.ProcessConversion(returnExpressions[i], returnValues[i], returnType);
2041
internal override void EnforceMerge(ResolveVisitor parentVisitor)
2043
ApplyReturnType(parentVisitor, SpecialType.UnknownType);
2048
#region Implicitly typed
2049
// Implicitly-typed lambdas are really complex, as the lambda depends on the target type (the delegate to which
2050
// the lambda is converted), but figuring out the target type might involve overload resolution (for method
2051
// calls in which the lambda is used as argument), which requires knowledge about the lamdba.
2053
// The implementation in NRefactory works like this:
2054
// 1. The lambda resolves to a ImplicitlyTypedLambda (derived from LambdaResolveResult).
2055
// The lambda body is not resolved yet (one of the few places where ResolveVisitor
2056
// deviates from the usual depth-first AST traversal).
2057
// 2. The parent statement is resolved as usual. This might require analyzing the lambda in detail (for example
2058
// as part of overload resolution). Such analysis happens using LambdaResolveResult.IsValid, where the caller
2059
// (i.e. the overload resolution algorithm) supplies the parameter types to the lambda body. For every IsValid()
2060
// call, a nested LambdaTypeHypothesis is constructed for analyzing the lambda using the supplied type assignment.
2061
// Multiple IsValid() calls may use several LambdaTypeHypothesis instances, one for each set of parameter types.
2062
// 3. When the resolver reports the conversions that occurred as part of the parent statement (as with any
2063
// conversions), the results from the LambdaTypeHypothesis corresponding to the actually chosen
2064
// conversion are merged into the main resolver.
2065
// 4. LambdaResolveResult.Body is set to the main resolve result from the chosen nested resolver. I think this
2066
// is the only place where NRefactory is mutating a ResolveResult (normally all resolve results are immutable).
2067
// As this step is guaranteed to occur before the resolver returns the LamdbaResolveResult to user code, the
2068
// mutation shouldn't cause any problems.
2069
sealed class ImplicitlyTypedLambda : LambdaBase
2071
readonly LambdaExpression lambda;
2072
readonly QuerySelectClause selectClause;
2074
readonly CSharpResolver storedContext;
2075
readonly CSharpParsedFile parsedFile;
2076
readonly List<LambdaTypeHypothesis> hypotheses = new List<LambdaTypeHypothesis>();
2077
internal IList<IParameter> parameters = new List<IParameter>();
2079
internal LambdaTypeHypothesis winningHypothesis;
2080
internal ResolveResult bodyResult;
2081
internal readonly ResolveVisitor parentVisitor;
2083
internal override bool IsUndecided {
2084
get { return winningHypothesis == null; }
2087
internal override AstNode LambdaExpression {
2089
if (selectClause != null)
2090
return selectClause.Expression;
2096
internal override AstNode BodyExpression {
2098
if (selectClause != null)
2099
return selectClause.Expression;
2105
public override ResolveResult Body {
2106
get { return bodyResult; }
2109
private ImplicitlyTypedLambda(ResolveVisitor parentVisitor)
2111
this.parentVisitor = parentVisitor;
2112
this.storedContext = parentVisitor.resolver;
2113
this.parsedFile = parentVisitor.parsedFile;
2114
this.bodyResult = parentVisitor.voidResult;
2117
public ImplicitlyTypedLambda(LambdaExpression lambda, ResolveVisitor parentVisitor)
2118
: this(parentVisitor)
2120
this.lambda = lambda;
2121
foreach (var pd in lambda.Parameters) {
2122
parameters.Add(new DefaultParameter(SpecialType.UnknownType, pd.Name, parentVisitor.MakeRegion(pd)));
2124
RegisterUndecidedLambda();
2127
public ImplicitlyTypedLambda(QuerySelectClause selectClause, IEnumerable<IParameter> parameters, ResolveVisitor parentVisitor)
2128
: this(parentVisitor)
2130
this.selectClause = selectClause;
2131
foreach (IParameter p in parameters)
2132
this.parameters.Add(p);
2134
RegisterUndecidedLambda();
2137
void RegisterUndecidedLambda()
2139
if (parentVisitor.undecidedLambdas == null)
2140
parentVisitor.undecidedLambdas = new List<LambdaBase>();
2141
parentVisitor.undecidedLambdas.Add(this);
2142
Log.WriteLine("Added undecided implicitly-typed lambda: " + this.LambdaExpression);
2145
public override IList<IParameter> Parameters {
2146
get { return parameters; }
2149
public override Conversion IsValid(IType[] parameterTypes, IType returnType, CSharpConversions conversions)
2151
Log.WriteLine("Testing validity of {0} for parameters ({1}) and return-type {2}...",
2152
this, string.Join<IType>(", ", parameterTypes), returnType);
2154
var hypothesis = GetHypothesis(parameterTypes);
2155
Conversion c = hypothesis.IsValid(returnType, conversions);
2157
Log.WriteLine("{0} is {1} for return-type {2}", hypothesis, c.IsValid ? "valid" : "invalid", returnType);
2161
public override IType GetInferredReturnType(IType[] parameterTypes)
2163
return GetHypothesis(parameterTypes).inferredReturnType;
2166
LambdaTypeHypothesis GetHypothesis(IType[] parameterTypes)
2168
if (parameterTypes.Length != parameters.Count)
2169
throw new ArgumentException("Incorrect parameter type count");
2170
foreach (var h in hypotheses) {
2172
for (int i = 0; i < parameterTypes.Length; i++) {
2173
if (!parameterTypes[i].Equals(h.parameterTypes[i])) {
2181
ResolveVisitor visitor = new ResolveVisitor(storedContext, parsedFile);
2182
var newHypothesis = new LambdaTypeHypothesis(this, parameterTypes, visitor, lambda != null ? lambda.Parameters : null);
2183
hypotheses.Add(newHypothesis);
2184
return newHypothesis;
2188
/// Get any hypothesis for this lambda.
2189
/// This method is used as fallback if the lambda isn't merged the normal way (AnonymousFunctionConversion)
2191
internal LambdaTypeHypothesis GetAnyHypothesis()
2193
if (winningHypothesis != null)
2194
return winningHypothesis;
2195
if (hypotheses.Count == 0) {
2196
// make a new hypothesis with unknown parameter types
2197
IType[] parameterTypes = new IType[parameters.Count];
2198
for (int i = 0; i < parameterTypes.Length; i++) {
2199
parameterTypes[i] = SpecialType.UnknownType;
2201
return GetHypothesis(parameterTypes);
2203
// We have the choice, so pick the hypothesis with the least missing parameter types
2204
LambdaTypeHypothesis bestHypothesis = hypotheses[0];
2205
int bestHypothesisUnknownParameters = bestHypothesis.CountUnknownParameters();
2206
for (int i = 1; i < hypotheses.Count; i++) {
2207
int c = hypotheses[i].CountUnknownParameters();
2208
if (c < bestHypothesisUnknownParameters ||
2209
(c == bestHypothesisUnknownParameters && hypotheses[i].success && !bestHypothesis.success))
2211
bestHypothesis = hypotheses[i];
2212
bestHypothesisUnknownParameters = c;
2215
return bestHypothesis;
2219
internal override void EnforceMerge(ResolveVisitor parentVisitor)
2221
GetAnyHypothesis().MergeInto(parentVisitor, SpecialType.UnknownType);
2224
public override bool IsImplicitlyTyped {
2225
get { return true; }
2228
public override bool IsAnonymousMethod {
2229
get { return false; }
2232
public override bool HasParameterList {
2233
get { return true; }
2236
public override bool IsAsync {
2237
get { return lambda != null && lambda.IsAsync; }
2240
public override string ToString()
2242
return "[ImplicitlyTypedLambda " + this.LambdaExpression + "]";
2247
/// Every possible set of parameter types gets its own 'hypothetical world'.
2248
/// It uses a nested ResolveVisitor that has its own resolve cache, so that resolve results cannot leave the hypothetical world.
2250
/// Only after overload resolution is applied and the actual parameter types are known, the winning hypothesis will be merged
2251
/// with the parent ResolveVisitor.
2252
/// This is done when the AnonymousFunctionConversion is applied on the parent visitor.
2254
sealed class LambdaTypeHypothesis : IResolveVisitorNavigator
2256
readonly ImplicitlyTypedLambda lambda;
2257
readonly IParameter[] lambdaParameters;
2258
internal readonly IType[] parameterTypes;
2259
readonly ResolveVisitor visitor;
2261
internal readonly IType inferredReturnType;
2262
IList<Expression> returnExpressions;
2263
IList<ResolveResult> returnValues;
2264
bool isValidAsVoidMethod;
2265
bool isEndpointUnreachable;
2266
internal bool success;
2268
public LambdaTypeHypothesis(ImplicitlyTypedLambda lambda, IType[] parameterTypes, ResolveVisitor visitor,
2269
ICollection<ParameterDeclaration> parameterDeclarations)
2271
Debug.Assert(parameterTypes.Length == lambda.Parameters.Count);
2273
this.lambda = lambda;
2274
this.parameterTypes = parameterTypes;
2275
this.visitor = visitor;
2276
visitor.SetNavigator(this);
2278
Log.WriteLine("Analyzing " + ToString() + "...");
2280
CSharpResolver oldResolver = visitor.resolver;
2281
visitor.resolver = visitor.resolver.WithIsWithinLambdaExpression(true);
2282
lambdaParameters = new IParameter[parameterTypes.Length];
2283
if (parameterDeclarations != null) {
2285
foreach (var pd in parameterDeclarations) {
2286
lambdaParameters[i] = new DefaultParameter(parameterTypes[i], pd.Name, visitor.MakeRegion(pd));
2287
visitor.resolver = visitor.resolver.AddVariable(lambdaParameters[i]);
2292
for (int i = 0; i < parameterTypes.Length; i++) {
2293
var p = lambda.Parameters[i];
2294
lambdaParameters[i] = new DefaultParameter(parameterTypes[i], p.Name, p.Region);
2295
visitor.resolver = visitor.resolver.AddVariable(lambdaParameters[i]);
2300
visitor.AnalyzeLambda(lambda.BodyExpression, lambda.IsAsync, out isValidAsVoidMethod, out isEndpointUnreachable, out inferredReturnType, out returnExpressions, out returnValues);
2301
visitor.resolver = oldResolver;
2303
Log.WriteLine("Finished analyzing " + ToString());
2306
ResolveVisitorNavigationMode IResolveVisitorNavigator.Scan(AstNode node)
2308
return ResolveVisitorNavigationMode.Resolve;
2311
void IResolveVisitorNavigator.Resolved(AstNode node, ResolveResult result)
2317
void IResolveVisitorNavigator.ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType)
2319
success &= conversion.IsValid;
2322
internal int CountUnknownParameters()
2325
foreach (IType t in parameterTypes) {
2326
if (t.Kind == TypeKind.Unknown)
2332
public Conversion IsValid(IType returnType, CSharpConversions conversions)
2334
bool valid = success && IsValidLambda(isValidAsVoidMethod, isEndpointUnreachable, lambda.IsAsync, returnValues, returnType, conversions);
2335
return new AnonymousFunctionConversion(returnType, this, valid);
2338
public void MergeInto(ResolveVisitor parentVisitor, IType returnType)
2340
if (returnType == null)
2341
throw new ArgumentNullException("returnType");
2342
if (parentVisitor != lambda.parentVisitor)
2343
throw new InvalidOperationException("parent visitor mismatch");
2345
if (lambda.winningHypothesis == this)
2347
else if (lambda.winningHypothesis != null)
2348
throw new InvalidOperationException("Trying to merge conflicting hypotheses");
2350
lambda.winningHypothesis = this;
2351
lambda.parameters = lambdaParameters; // replace untyped parameters with typed parameters
2352
if (lambda.BodyExpression is Expression && returnValues.Count == 1) {
2353
lambda.bodyResult = returnValues[0];
2356
Log.WriteLine("Applying return type {0} to implicitly-typed lambda {1}", returnType, lambda.LambdaExpression);
2358
returnType = parentVisitor.UnpackTask(returnType);
2359
if (returnType.Kind != TypeKind.Void) {
2360
for (int i = 0; i < returnExpressions.Count; i++) {
2361
visitor.ProcessConversion(returnExpressions[i], returnValues[i], returnType);
2365
visitor.MergeUndecidedLambdas();
2366
Log.WriteLine("Merging " + ToString());
2367
foreach (var pair in visitor.resolverBeforeDict) {
2368
Debug.Assert(!parentVisitor.resolverBeforeDict.ContainsKey(pair.Key));
2369
parentVisitor.resolverBeforeDict[pair.Key] = pair.Value;
2371
foreach (var pair in visitor.resolverAfterDict) {
2372
Debug.Assert(!parentVisitor.resolverAfterDict.ContainsKey(pair.Key));
2373
parentVisitor.resolverAfterDict[pair.Key] = pair.Value;
2375
foreach (var pair in visitor.resolveResultCache) {
2376
parentVisitor.StoreResult(pair.Key, pair.Value);
2378
parentVisitor.ImportConversions(visitor);
2379
parentVisitor.undecidedLambdas.Remove(lambda);
2382
public override string ToString()
2384
StringBuilder b = new StringBuilder();
2385
b.Append("[LambdaTypeHypothesis (");
2386
for (int i = 0; i < parameterTypes.Length; i++) {
2387
if (i > 0) b.Append(", ");
2388
b.Append(parameterTypes[i]);
2390
b.Append(lambda.Parameters[i].Name);
2393
b.Append(lambda.BodyExpression.ToString());
2395
return b.ToString();
2400
#region MergeUndecidedLambdas
2401
abstract class LambdaBase : LambdaResolveResult
2403
internal abstract bool IsUndecided { get; }
2404
internal abstract AstNode LambdaExpression { get; }
2405
internal abstract AstNode BodyExpression { get; }
2407
internal abstract void EnforceMerge(ResolveVisitor parentVisitor);
2410
void MergeUndecidedLambdas()
2412
if (undecidedLambdas == null || undecidedLambdas.Count == 0)
2414
Log.WriteLine("MergeUndecidedLambdas()...");
2416
while (undecidedLambdas.Count > 0) {
2417
LambdaBase lambda = undecidedLambdas[0];
2418
ResolveParentForConversion(lambda.LambdaExpression);
2419
if (lambda.IsUndecided) {
2420
// Lambda wasn't merged by resolving its parent -> enforce merging
2421
Log.WriteLine("Lambda wasn't merged by conversion - enforce merging");
2422
lambda.EnforceMerge(this);
2426
Log.WriteLine("MergeUndecidedLambdas() finished.");
2429
void ResolveParentForConversion(AstNode expression)
2431
AstNode parent = expression.Parent;
2432
// Continue going upwards until we find a node that can be resolved and provides
2433
// an expected type.
2434
while (ParenthesizedExpression.ActsAsParenthesizedExpression(parent) || CSharpAstResolver.IsUnresolvableNode(parent)) {
2435
parent = parent.Parent;
2437
CSharpResolver storedResolver;
2438
if (parent != null && resolverBeforeDict.TryGetValue(parent, out storedResolver)) {
2439
Log.WriteLine("Trying to resolve '" + parent + "' in order to find the conversion applied to '" + expression + "'...");
2441
ResetContext(storedResolver, delegate { Resolve(parent); });
2444
Log.WriteLine("Could not find a suitable parent for '" + expression + "'");
2449
#region AnalyzeLambda
2450
IType GetTaskType(IType resultType)
2452
if (resultType.Kind == TypeKind.Unknown)
2453
return SpecialType.UnknownType;
2454
if (resultType.Kind == TypeKind.Void)
2455
return resolver.Compilation.FindType(KnownTypeCode.Task);
2457
ITypeDefinition def = resolver.Compilation.FindType(KnownTypeCode.TaskOfT).GetDefinition();
2459
return new ParameterizedType(def, new[] { resultType });
2461
return SpecialType.UnknownType;
2464
void AnalyzeLambda(AstNode body, bool isAsync, out bool isValidAsVoidMethod, out bool isEndpointUnreachable, out IType inferredReturnType, out IList<Expression> returnExpressions, out IList<ResolveResult> returnValues)
2466
isEndpointUnreachable = false;
2467
Expression expr = body as Expression;
2469
isValidAsVoidMethod = ExpressionPermittedAsStatement(expr);
2470
returnExpressions = new [] { expr };
2471
returnValues = new[] { Resolve(expr) };
2472
inferredReturnType = returnValues[0].Type;
2476
AnalyzeLambdaVisitor alv = new AnalyzeLambdaVisitor();
2477
body.AcceptVisitor(alv);
2478
isValidAsVoidMethod = (alv.ReturnExpressions.Count == 0);
2479
if (alv.HasVoidReturnStatements) {
2480
returnExpressions = EmptyList<Expression>.Instance;
2481
returnValues = EmptyList<ResolveResult>.Instance;
2482
inferredReturnType = resolver.Compilation.FindType(KnownTypeCode.Void);
2484
returnExpressions = alv.ReturnExpressions;
2485
returnValues = new ResolveResult[returnExpressions.Count];
2486
for (int i = 0; i < returnValues.Count; i++) {
2487
returnValues[i] = resolveResultCache[returnExpressions[i]];
2489
TypeInference ti = new TypeInference(resolver.Compilation, resolver.conversions);
2491
inferredReturnType = ti.GetBestCommonType(returnValues, out tiSuccess);
2492
// Failure to infer a return type does not make the lambda invalid,
2493
// so we can ignore the 'tiSuccess' value
2494
if (isValidAsVoidMethod && returnExpressions.Count == 0 && body is Statement) {
2495
var reachabilityAnalysis = ReachabilityAnalysis.Create(
2496
(Statement)body, (node, _) => resolveResultCache[node],
2497
resolver.CurrentTypeResolveContext, cancellationToken);
2498
isEndpointUnreachable = !reachabilityAnalysis.IsEndpointReachable((Statement)body);
2503
inferredReturnType = GetTaskType(inferredReturnType);
2504
Log.WriteLine("Lambda return type was inferred to: " + inferredReturnType);
2507
static bool ExpressionPermittedAsStatement(Expression expr)
2509
UnaryOperatorExpression uoe = expr as UnaryOperatorExpression;
2511
switch (uoe.Operator) {
2512
case UnaryOperatorType.Increment:
2513
case UnaryOperatorType.Decrement:
2514
case UnaryOperatorType.PostIncrement:
2515
case UnaryOperatorType.PostDecrement:
2516
case UnaryOperatorType.Await:
2522
return expr is InvocationExpression
2523
|| expr is ObjectCreateExpression
2524
|| expr is AssignmentExpression;
2527
static bool IsValidLambda(bool isValidAsVoidMethod, bool isEndpointUnreachable, bool isAsync, IList<ResolveResult> returnValues, IType returnType, CSharpConversions conversions)
2529
if (returnType.Kind == TypeKind.Void) {
2530
// Lambdas that are valid statement lambdas or expression lambdas with a statement-expression
2531
// can be converted to delegates with void return type.
2532
// This holds for both async and regular lambdas.
2533
return isValidAsVoidMethod;
2534
} else if (isAsync && IsTask(returnType) && returnType.TypeParameterCount == 0) {
2535
// Additionally, async lambdas with the above property can be converted to non-generic Task.
2536
return isValidAsVoidMethod;
2538
if (returnValues.Count == 0)
2539
return isEndpointUnreachable;
2541
// async lambdas must return Task<T>
2542
if (!(IsTask(returnType) && returnType.TypeParameterCount == 1))
2544
// unpack Task<T> for testing the implicit conversions
2545
returnType = ((ParameterizedType)returnType).GetTypeArgument(0);
2547
foreach (ResolveResult returnRR in returnValues) {
2548
if (!conversions.ImplicitConversion(returnRR, returnType).IsValid)
2556
/// Gets the T in Task<T>.
2557
/// Returns void for non-generic Task.
2559
IType UnpackTask(IType type)
2563
if (type.TypeParameterCount == 0)
2564
return resolver.Compilation.FindType(KnownTypeCode.Void);
2566
return ((ParameterizedType)type).GetTypeArgument(0);
2570
/// Gets whether the specified type is Task or Task<T>.
2572
static bool IsTask(IType type)
2574
ITypeDefinition def = type.GetDefinition();
2576
if (def.KnownTypeCode == KnownTypeCode.Task)
2578
if (def.KnownTypeCode == KnownTypeCode.TaskOfT)
2579
return type is ParameterizedType;
2584
sealed class AnalyzeLambdaVisitor : DepthFirstAstVisitor
2586
public bool HasVoidReturnStatements;
2587
public List<Expression> ReturnExpressions = new List<Expression>();
2589
public override void VisitReturnStatement(ReturnStatement returnStatement)
2591
Expression expr = returnStatement.Expression;
2593
HasVoidReturnStatements = true;
2595
ReturnExpressions.Add(expr);
2599
public override void VisitAnonymousMethodExpression(AnonymousMethodExpression anonymousMethodExpression)
2601
// don't go into nested lambdas
2604
public override void VisitLambdaExpression(LambdaExpression lambdaExpression)
2606
// don't go into nested lambdas
2612
#region ForEach Statement
2613
ResolveResult IAstVisitor<ResolveResult>.VisitForeachStatement(ForeachStatement foreachStatement)
2615
var compilation = resolver.Compilation;
2616
ResolveResult expression = Resolve(foreachStatement.InExpression);
2617
bool isImplicitlyTypedVariable = IsVar(foreachStatement.VariableType);
2618
var memberLookup = resolver.CreateMemberLookup();
2620
IType collectionType, enumeratorType, elementType;
2621
ResolveResult getEnumeratorInvocation;
2622
ResolveResult currentRR = null;
2623
// C# 4.0 spec: Ā§8.8.4 The foreach statement
2624
if (expression.Type.Kind == TypeKind.Array || expression.Type.Kind == TypeKind.Dynamic) {
2625
collectionType = compilation.FindType(KnownTypeCode.IEnumerable);
2626
enumeratorType = compilation.FindType(KnownTypeCode.IEnumerator);
2627
if (expression.Type.Kind == TypeKind.Array) {
2628
elementType = ((ArrayType)expression.Type).ElementType;
2630
elementType = isImplicitlyTypedVariable ? SpecialType.Dynamic : compilation.FindType(KnownTypeCode.Object);
2632
getEnumeratorInvocation = resolver.ResolveCast(collectionType, expression);
2633
getEnumeratorInvocation = resolver.ResolveMemberAccess(getEnumeratorInvocation, "GetEnumerator", EmptyList<IType>.Instance, NameLookupMode.InvocationTarget);
2634
getEnumeratorInvocation = resolver.ResolveInvocation(getEnumeratorInvocation, new ResolveResult[0]);
2636
var getEnumeratorMethodGroup = memberLookup.Lookup(expression, "GetEnumerator", EmptyList<IType>.Instance, true) as MethodGroupResolveResult;
2637
if (getEnumeratorMethodGroup != null) {
2638
var or = getEnumeratorMethodGroup.PerformOverloadResolution(compilation, new ResolveResult[0]);
2639
if (or.FoundApplicableCandidate && !or.IsAmbiguous && !or.BestCandidate.IsStatic && or.BestCandidate.IsPublic) {
2640
collectionType = expression.Type;
2641
getEnumeratorInvocation = or.CreateResolveResult(expression);
2642
enumeratorType = getEnumeratorInvocation.Type;
2643
currentRR = memberLookup.Lookup(new ResolveResult(enumeratorType), "Current", EmptyList<IType>.Instance, false);
2644
elementType = currentRR.Type;
2646
CheckForEnumerableInterface(expression, out collectionType, out enumeratorType, out elementType, out getEnumeratorInvocation);
2649
CheckForEnumerableInterface(expression, out collectionType, out enumeratorType, out elementType, out getEnumeratorInvocation);
2652
IMethod moveNextMethod = null;
2653
var moveNextMethodGroup = memberLookup.Lookup(new ResolveResult(enumeratorType), "MoveNext", EmptyList<IType>.Instance, false) as MethodGroupResolveResult;
2654
if (moveNextMethodGroup != null) {
2655
var or = moveNextMethodGroup.PerformOverloadResolution(compilation, new ResolveResult[0]);
2656
moveNextMethod = or.GetBestCandidateWithSubstitutedTypeArguments() as IMethod;
2659
if (currentRR == null)
2660
currentRR = memberLookup.Lookup(new ResolveResult(enumeratorType), "Current", EmptyList<IType>.Instance, false);
2661
IProperty currentProperty = null;
2662
if (currentRR is MemberResolveResult)
2663
currentProperty = ((MemberResolveResult)currentRR).Member as IProperty;
2664
// end of foreach resolve logic
2665
// back to resolve visitor:
2667
resolver = resolver.PushBlock();
2669
if (isImplicitlyTypedVariable) {
2670
StoreCurrentState(foreachStatement.VariableType);
2671
StoreResult(foreachStatement.VariableType, new TypeResolveResult(elementType));
2672
v = MakeVariable(elementType, foreachStatement.VariableNameToken);
2674
IType variableType = ResolveType(foreachStatement.VariableType);
2675
v = MakeVariable(variableType, foreachStatement.VariableNameToken);
2677
StoreCurrentState(foreachStatement.VariableNameToken);
2678
resolver = resolver.AddVariable(v);
2680
StoreResult(foreachStatement.VariableNameToken, new LocalResolveResult(v));
2682
Scan(foreachStatement.EmbeddedStatement);
2683
resolver = resolver.PopBlock();
2684
return new ForEachResolveResult(getEnumeratorInvocation, collectionType, enumeratorType, elementType,
2685
v, currentProperty, moveNextMethod, voidResult.Type);
2688
void CheckForEnumerableInterface(ResolveResult expression, out IType collectionType, out IType enumeratorType, out IType elementType, out ResolveResult getEnumeratorInvocation)
2690
var compilation = resolver.Compilation;
2692
elementType = GetElementTypeFromIEnumerable(expression.Type, compilation, false, out isGeneric);
2693
if (isGeneric == true) {
2694
ITypeDefinition enumerableOfT = compilation.FindType(KnownTypeCode.IEnumerableOfT).GetDefinition();
2695
if (enumerableOfT != null)
2696
collectionType = new ParameterizedType(enumerableOfT, new [] { elementType });
2698
collectionType = SpecialType.UnknownType;
2700
ITypeDefinition enumeratorOfT = compilation.FindType(KnownTypeCode.IEnumeratorOfT).GetDefinition();
2701
if (enumeratorOfT != null)
2702
enumeratorType = new ParameterizedType(enumeratorOfT, new [] { elementType });
2704
enumeratorType = SpecialType.UnknownType;
2705
} else if (isGeneric == false) {
2706
collectionType = compilation.FindType(KnownTypeCode.IEnumerable);
2707
enumeratorType = compilation.FindType(KnownTypeCode.IEnumerator);
2709
collectionType = SpecialType.UnknownType;
2710
enumeratorType = SpecialType.UnknownType;
2712
getEnumeratorInvocation = resolver.ResolveCast(collectionType, expression);
2713
getEnumeratorInvocation = resolver.ResolveMemberAccess(getEnumeratorInvocation, "GetEnumerator", EmptyList<IType>.Instance, NameLookupMode.InvocationTarget);
2714
getEnumeratorInvocation = resolver.ResolveInvocation(getEnumeratorInvocation, new ResolveResult[0]);
2718
#region Local Variable Scopes (Block Statements)
2719
ResolveResult IAstVisitor<ResolveResult>.VisitBlockStatement(BlockStatement blockStatement)
2721
resolver = resolver.PushBlock();
2722
ScanChildren(blockStatement);
2723
resolver = resolver.PopBlock();
2727
ResolveResult IAstVisitor<ResolveResult>.VisitUsingStatement(UsingStatement usingStatement)
2729
resolver = resolver.PushBlock();
2730
if (resolverEnabled) {
2731
for (AstNode child = usingStatement.FirstChild; child != null; child = child.NextSibling) {
2732
if (child.Role == UsingStatement.ResourceAcquisitionRole && child is Expression) {
2733
ResolveAndProcessConversion((Expression)child, resolver.Compilation.FindType(KnownTypeCode.IDisposable));
2739
ScanChildren(usingStatement);
2741
resolver = resolver.PopBlock();
2742
return resolverEnabled ? voidResult : null;
2745
ResolveResult IAstVisitor<ResolveResult>.VisitFixedStatement(FixedStatement fixedStatement)
2747
resolver = resolver.PushBlock();
2748
IType type = ResolveType(fixedStatement.Type);
2749
foreach (VariableInitializer vi in fixedStatement.Variables) {
2750
resolver = resolver.AddVariable(MakeVariable(type, vi.NameToken));
2753
Scan(fixedStatement.EmbeddedStatement);
2754
resolver = resolver.PopBlock();
2758
ResolveResult IAstVisitor<ResolveResult>.VisitSwitchStatement(SwitchStatement switchStatement)
2760
resolver = resolver.PushBlock();
2761
ScanChildren(switchStatement);
2762
resolver = resolver.PopBlock();
2766
ResolveResult IAstVisitor<ResolveResult>.VisitCatchClause(CatchClause catchClause)
2768
resolver = resolver.PushBlock();
2769
if (string.IsNullOrEmpty(catchClause.VariableName)) {
2770
Scan(catchClause.Type);
2772
//DomRegion region = MakeRegion(catchClause.VariableNameToken);
2773
StoreCurrentState(catchClause.VariableNameToken);
2774
IVariable v = MakeVariable(ResolveType(catchClause.Type), catchClause.VariableNameToken);
2775
resolver = resolver.AddVariable(v);
2776
StoreResult(catchClause.VariableNameToken, new LocalResolveResult(v));
2778
Scan(catchClause.Body);
2779
resolver = resolver.PopBlock();
2784
#region VariableDeclarationStatement
2785
ResolveResult IAstVisitor<ResolveResult>.VisitVariableDeclarationStatement(VariableDeclarationStatement variableDeclarationStatement)
2787
bool isConst = (variableDeclarationStatement.Modifiers & Modifiers.Const) != 0;
2788
if (!isConst && IsVar(variableDeclarationStatement.Type) && variableDeclarationStatement.Variables.Count == 1) {
2789
VariableInitializer vi = variableDeclarationStatement.Variables.Single();
2790
StoreCurrentState(variableDeclarationStatement.Type);
2791
IType type = Resolve(vi.Initializer).Type;
2792
StoreResult(variableDeclarationStatement.Type, new TypeResolveResult(type));
2793
IVariable v = MakeVariable(type, vi.NameToken);
2794
resolver = resolver.AddVariable(v);
2797
IType type = ResolveType(variableDeclarationStatement.Type);
2799
foreach (VariableInitializer vi in variableDeclarationStatement.Variables) {
2802
v = MakeConstant(type, vi.NameToken, Resolve(vi.Initializer).ConstantValue);
2804
v = MakeVariable(type, vi.NameToken);
2806
resolver = resolver.AddVariable(v);
2814
#region Condition Statements
2815
ResolveResult IAstVisitor<ResolveResult>.VisitForStatement(ForStatement forStatement)
2817
resolver = resolver.PushBlock();
2818
var result = HandleConditionStatement(forStatement);
2819
resolver = resolver.PopBlock();
2823
ResolveResult IAstVisitor<ResolveResult>.VisitIfElseStatement(IfElseStatement ifElseStatement)
2825
return HandleConditionStatement(ifElseStatement);
2828
ResolveResult IAstVisitor<ResolveResult>.VisitWhileStatement(WhileStatement whileStatement)
2830
return HandleConditionStatement(whileStatement);
2833
ResolveResult IAstVisitor<ResolveResult>.VisitDoWhileStatement(DoWhileStatement doWhileStatement)
2835
return HandleConditionStatement(doWhileStatement);
2838
ResolveResult HandleConditionStatement(Statement conditionStatement)
2840
if (resolverEnabled) {
2841
for (AstNode child = conditionStatement.FirstChild; child != null; child = child.NextSibling) {
2842
if (child.Role == Roles.Condition) {
2843
Expression condition = (Expression)child;
2844
ResolveResult conditionRR = Resolve(condition);
2845
ResolveResult convertedRR = resolver.ResolveCondition(conditionRR);
2846
if (convertedRR != conditionRR)
2847
ProcessConversionResult(condition, convertedRR as ConversionResolveResult);
2854
ScanChildren(conditionStatement);
2860
#region Return Statements
2861
ResolveResult IAstVisitor<ResolveResult>.VisitReturnStatement(ReturnStatement returnStatement)
2863
if (resolverEnabled && !resolver.IsWithinLambdaExpression && resolver.CurrentMember != null) {
2864
IType type = resolver.CurrentMember.ReturnType;
2866
var methodDecl = returnStatement.Ancestors.OfType<EntityDeclaration>().FirstOrDefault();
2867
if (methodDecl != null && (methodDecl.Modifiers & Modifiers.Async) == Modifiers.Async)
2868
type = UnpackTask(type);
2870
ResolveAndProcessConversion(returnStatement.Expression, type);
2872
Scan(returnStatement.Expression);
2874
return resolverEnabled ? voidResult : null;
2877
ResolveResult IAstVisitor<ResolveResult>.VisitYieldReturnStatement(YieldReturnStatement yieldStatement)
2879
if (resolverEnabled && resolver.CurrentMember != null) {
2880
IType returnType = resolver.CurrentMember.ReturnType;
2882
IType elementType = GetElementTypeFromIEnumerable(returnType, resolver.Compilation, true, out isGeneric);
2883
ResolveAndProcessConversion(yieldStatement.Expression, elementType);
2885
Scan(yieldStatement.Expression);
2887
return resolverEnabled ? voidResult : null;
2890
ResolveResult IAstVisitor<ResolveResult>.VisitYieldBreakStatement(YieldBreakStatement yieldBreakStatement)
2896
#region Other statements
2897
ResolveResult IAstVisitor<ResolveResult>.VisitExpressionStatement(ExpressionStatement expressionStatement)
2899
ScanChildren(expressionStatement);
2903
ResolveResult IAstVisitor<ResolveResult>.VisitLockStatement(LockStatement lockStatement)
2905
ScanChildren(lockStatement);
2909
ResolveResult IAstVisitor<ResolveResult>.VisitEmptyStatement(EmptyStatement emptyStatement)
2914
ResolveResult IAstVisitor<ResolveResult>.VisitBreakStatement(BreakStatement breakStatement)
2919
ResolveResult IAstVisitor<ResolveResult>.VisitContinueStatement(ContinueStatement continueStatement)
2924
ResolveResult IAstVisitor<ResolveResult>.VisitThrowStatement(ThrowStatement throwStatement)
2926
if (resolverEnabled) {
2927
ResolveAndProcessConversion(throwStatement.Expression, resolver.Compilation.FindType(KnownTypeCode.Exception));
2930
Scan(throwStatement.Expression);
2935
ResolveResult IAstVisitor<ResolveResult>.VisitTryCatchStatement(TryCatchStatement tryCatchStatement)
2937
ScanChildren(tryCatchStatement);
2941
ResolveResult IAstVisitor<ResolveResult>.VisitGotoCaseStatement(GotoCaseStatement gotoCaseStatement)
2943
ScanChildren(gotoCaseStatement);
2947
ResolveResult IAstVisitor<ResolveResult>.VisitGotoDefaultStatement(GotoDefaultStatement gotoDefaultStatement)
2952
ResolveResult IAstVisitor<ResolveResult>.VisitGotoStatement(GotoStatement gotoStatement)
2957
ResolveResult IAstVisitor<ResolveResult>.VisitLabelStatement(LabelStatement labelStatement)
2962
ResolveResult IAstVisitor<ResolveResult>.VisitUnsafeStatement(UnsafeStatement unsafeStatement)
2964
resolver = resolver.PushBlock();
2965
ScanChildren(unsafeStatement);
2966
resolver = resolver.PopBlock();
2971
#region Local Variable Type Inference
2972
static bool IsVar(AstNode returnType)
2974
SimpleType st = returnType as SimpleType;
2975
return st != null && st.Identifier == "var" && st.TypeArguments.Count == 0;
2978
IVariable MakeVariable(IType type, Identifier variableName)
2980
return new SimpleVariable(MakeRegion(variableName), type, variableName.Name);
2983
IVariable MakeConstant(IType type, Identifier variableName, object constantValue)
2985
return new SimpleConstant(MakeRegion(variableName), type, variableName.Name, constantValue);
2988
class SimpleVariable : IVariable
2990
readonly DomRegion region;
2991
readonly IType type;
2992
readonly string name;
2994
public SimpleVariable(DomRegion region, IType type, string name)
2996
Debug.Assert(type != null);
2997
Debug.Assert(name != null);
2998
this.region = region;
3003
public string Name {
3004
get { return name; }
3007
public DomRegion Region {
3008
get { return region; }
3012
get { return type; }
3015
public virtual bool IsConst {
3016
get { return false; }
3019
public virtual object ConstantValue {
3020
get { return null; }
3023
public override string ToString()
3025
return type.ToString() + " " + name + ";";
3029
sealed class SimpleConstant : SimpleVariable
3031
readonly object constantValue;
3033
public SimpleConstant(DomRegion region, IType type, string name, object constantValue)
3034
: base(region, type, name)
3036
this.constantValue = constantValue;
3039
public override bool IsConst {
3040
get { return true; }
3043
public override object ConstantValue {
3044
get { return constantValue; }
3047
public override string ToString()
3049
return Type.ToString() + " " + Name + " = " + new PrimitiveExpression(constantValue).ToString() + ";";
3053
static IType GetElementTypeFromIEnumerable(IType collectionType, ICompilation compilation, bool allowIEnumerator, out bool? isGeneric)
3055
bool foundNonGenericIEnumerable = false;
3056
foreach (IType baseType in collectionType.GetAllBaseTypes()) {
3057
ITypeDefinition baseTypeDef = baseType.GetDefinition();
3058
if (baseTypeDef != null) {
3059
KnownTypeCode typeCode = baseTypeDef.KnownTypeCode;
3060
if (typeCode == KnownTypeCode.IEnumerableOfT || (allowIEnumerator && typeCode == KnownTypeCode.IEnumeratorOfT)) {
3061
ParameterizedType pt = baseType as ParameterizedType;
3064
return pt.GetTypeArgument(0);
3067
if (typeCode == KnownTypeCode.IEnumerable || (allowIEnumerator && typeCode == KnownTypeCode.IEnumerator))
3068
foundNonGenericIEnumerable = true;
3071
// System.Collections.IEnumerable found in type hierarchy -> Object is element type.
3072
if (foundNonGenericIEnumerable) {
3074
return compilation.FindType(KnownTypeCode.Object);
3077
return SpecialType.UnknownType;
3082
ResolveResult IAstVisitor<ResolveResult>.VisitAttribute(Attribute attribute)
3084
var type = ResolveType(attribute.Type);
3086
// Separate arguments into ctor arguments and non-ctor arguments:
3087
var constructorArguments = attribute.Arguments.Where(a => !(a is NamedExpression));
3088
var nonConstructorArguments = attribute.Arguments.OfType<NamedExpression>();
3090
// Scan the non-constructor arguments
3091
resolver = resolver.PushObjectInitializer(new InitializedObjectResolveResult(type));
3092
List<ResolveResult> initializerStatements = new List<ResolveResult>();
3093
foreach (var arg in nonConstructorArguments)
3094
HandleNamedExpression(arg, initializerStatements);
3095
resolver = resolver.PopObjectInitializer();
3097
// Resolve the ctor arguments and find the matching ctor overload
3098
string[] argumentNames;
3099
ResolveResult[] arguments = GetArguments(constructorArguments, out argumentNames);
3100
ResolveResult rr = resolver.ResolveObjectCreation(type, arguments, argumentNames, false, initializerStatements);
3101
ProcessConversionsInInvocation(null, constructorArguments, rr as CSharpInvocationResolveResult);
3105
ResolveResult IAstVisitor<ResolveResult>.VisitAttributeSection(AttributeSection attributeSection)
3107
ScanChildren(attributeSection);
3112
#region Using Declaration
3113
ResolveResult IAstVisitor<ResolveResult>.VisitUsingDeclaration(UsingDeclaration usingDeclaration)
3115
ScanChildren(usingDeclaration);
3119
ResolveResult IAstVisitor<ResolveResult>.VisitUsingAliasDeclaration(UsingAliasDeclaration usingDeclaration)
3121
ScanChildren(usingDeclaration);
3125
ResolveResult IAstVisitor<ResolveResult>.VisitExternAliasDeclaration(ExternAliasDeclaration externAliasDeclaration)
3131
#region Type References
3132
ResolveResult IAstVisitor<ResolveResult>.VisitPrimitiveType(PrimitiveType primitiveType)
3134
if (!resolverEnabled)
3136
KnownTypeCode typeCode = primitiveType.KnownTypeCode;
3137
if (typeCode == KnownTypeCode.None && primitiveType.Parent is Constraint && primitiveType.Role == Roles.BaseType) {
3138
switch (primitiveType.Keyword) {
3145
IType type = resolver.Compilation.FindType(typeCode);
3146
return new TypeResolveResult(type);
3149
ResolveResult IAstVisitor<ResolveResult>.VisitSimpleType(SimpleType simpleType)
3151
if (!resolverEnabled) {
3152
ScanChildren(simpleType);
3156
// Figure out the correct lookup mode:
3157
NameLookupMode lookupMode = GetNameLookupMode(simpleType);
3159
var typeArguments = ResolveTypeArguments(simpleType.TypeArguments);
3160
Identifier identifier = simpleType.IdentifierToken;
3161
if (string.IsNullOrEmpty(identifier.Name))
3162
return new TypeResolveResult(SpecialType.UnboundTypeArgument);
3163
ResolveResult rr = resolver.LookupSimpleNameOrTypeName(identifier.Name, typeArguments, lookupMode);
3164
if (simpleType.Parent is Attribute && !identifier.IsVerbatim) {
3165
var withSuffix = resolver.LookupSimpleNameOrTypeName(identifier.Name + "Attribute", typeArguments, lookupMode);
3166
if (AttributeTypeReference.PreferAttributeTypeWithSuffix(rr.Type, withSuffix.Type, resolver.Compilation))
3172
NameLookupMode GetNameLookupMode(AstType type)
3174
AstType outermostType = type;
3175
while (outermostType.Parent is AstType)
3176
outermostType = (AstType)outermostType.Parent;
3177
NameLookupMode lookupMode = NameLookupMode.Type;
3178
if (outermostType.Parent is UsingDeclaration || outermostType.Parent is UsingAliasDeclaration) {
3179
lookupMode = NameLookupMode.TypeInUsingDeclaration;
3180
} else if (outermostType.Parent is TypeDeclaration && outermostType.Role == Roles.BaseType) {
3181
lookupMode = NameLookupMode.BaseTypeReference;
3186
ResolveResult IAstVisitor<ResolveResult>.VisitMemberType(MemberType memberType)
3188
ResolveResult target;
3189
if (memberType.IsDoubleColon && memberType.Target is SimpleType) {
3190
SimpleType t = (SimpleType)memberType.Target;
3191
StoreCurrentState(t);
3192
target = resolver.ResolveAlias(t.Identifier);
3193
StoreResult(t, target);
3195
if (!resolverEnabled) {
3196
ScanChildren(memberType);
3199
target = Resolve(memberType.Target);
3202
NameLookupMode lookupMode = GetNameLookupMode(memberType);
3203
var typeArguments = ResolveTypeArguments(memberType.TypeArguments);
3204
Identifier identifier = memberType.MemberNameToken;
3205
ResolveResult rr = resolver.ResolveMemberAccess(target, identifier.Name, typeArguments, lookupMode);
3206
if (memberType.Parent is Attribute && !identifier.IsVerbatim) {
3207
var withSuffix = resolver.ResolveMemberAccess(target, identifier.Name + "Attribute", typeArguments, lookupMode);
3208
if (AttributeTypeReference.PreferAttributeTypeWithSuffix(rr.Type, withSuffix.Type, resolver.Compilation))
3214
ResolveResult IAstVisitor<ResolveResult>.VisitComposedType(ComposedType composedType)
3216
if (!resolverEnabled) {
3217
ScanChildren(composedType);
3220
IType t = ResolveType(composedType.BaseType);
3221
if (composedType.HasNullableSpecifier) {
3222
t = NullableType.Create(resolver.Compilation, t);
3224
for (int i = 0; i < composedType.PointerRank; i++) {
3225
t = new PointerType(t);
3227
foreach (var a in composedType.ArraySpecifiers.Reverse()) {
3228
t = new ArrayType(resolver.Compilation, t, a.Dimensions);
3230
return new TypeResolveResult(t);
3234
#region Query Expressions
3235
ResolveResult IAstVisitor<ResolveResult>.VisitQueryExpression(QueryExpression queryExpression)
3237
resolver = resolver.PushBlock();
3238
var oldQueryResult = currentQueryResult;
3239
var oldCancellationToken = cancellationToken;
3241
// Because currentQueryResult isn't part of the stored state,
3242
// query expressions must be resolved in a single operation.
3243
// This means we can't allow cancellation within the query expression.
3244
cancellationToken = CancellationToken.None;
3245
currentQueryResult = null;
3246
foreach (var clause in queryExpression.Clauses) {
3247
currentQueryResult = Resolve(clause);
3249
return currentQueryResult;
3251
currentQueryResult = oldQueryResult;
3252
cancellationToken = oldCancellationToken;
3253
resolver = resolver.PopBlock();
3257
IType GetTypeForQueryVariable(IType type)
3259
// This assumes queries are only used on IEnumerable.
3260
// We might want to look at the signature of a LINQ method (e.g. Select) instead.
3262
return GetElementTypeFromIEnumerable(type, resolver.Compilation, false, out isGeneric);
3265
ResolveResult MakeTransparentIdentifierResolveResult()
3267
return new ResolveResult(new AnonymousType(resolver.Compilation, EmptyList<IUnresolvedProperty>.Instance));
3270
sealed class QueryExpressionLambdaConversion : Conversion
3272
internal readonly IType[] ParameterTypes;
3274
public QueryExpressionLambdaConversion(IType[] parameterTypes)
3276
this.ParameterTypes = parameterTypes;
3279
public override bool IsImplicit {
3280
get { return true; }
3283
public override bool IsAnonymousFunctionConversion {
3284
get { return true; }
3288
sealed class QueryExpressionLambda : LambdaResolveResult
3290
readonly IParameter[] parameters;
3291
readonly ResolveResult bodyExpression;
3293
internal IType[] inferredParameterTypes;
3295
public QueryExpressionLambda(int parameterCount, ResolveResult bodyExpression)
3297
this.parameters = new IParameter[parameterCount];
3298
for (int i = 0; i < parameterCount; i++) {
3299
parameters[i] = new DefaultParameter(SpecialType.UnknownType, "x" + i);
3301
this.bodyExpression = bodyExpression;
3304
public override IList<IParameter> Parameters {
3305
get { return parameters; }
3308
public override Conversion IsValid(IType[] parameterTypes, IType returnType, CSharpConversions conversions)
3310
if (parameterTypes.Length == parameters.Length) {
3311
this.inferredParameterTypes = parameterTypes;
3312
return new QueryExpressionLambdaConversion(parameterTypes);
3314
return Conversion.None;
3318
public override bool IsAsync {
3319
get { return false; }
3322
public override bool IsImplicitlyTyped {
3323
get { return true; }
3326
public override bool IsAnonymousMethod {
3327
get { return false; }
3330
public override bool HasParameterList {
3331
get { return true; }
3334
public override ResolveResult Body {
3335
get { return bodyExpression; }
3338
public override IType GetInferredReturnType(IType[] parameterTypes)
3340
return bodyExpression.Type;
3343
public override string ToString()
3345
return string.Format("[QueryExpressionLambda ({0}) => {1}]", string.Join(",", parameters.Select(p => p.Name)), bodyExpression);
3349
QueryClause GetPreviousQueryClause(QueryClause clause)
3351
for (AstNode node = clause.PrevSibling; node != null; node = node.PrevSibling) {
3352
if (node.Role == QueryExpression.ClauseRole)
3353
return (QueryClause)node;
3358
QueryClause GetNextQueryClause(QueryClause clause)
3360
for (AstNode node = clause.NextSibling; node != null; node = node.NextSibling) {
3361
if (node.Role == QueryExpression.ClauseRole)
3362
return (QueryClause)node;
3367
ResolveResult IAstVisitor<ResolveResult>.VisitQueryFromClause(QueryFromClause queryFromClause)
3369
ResolveResult result = errorResult;
3370
ResolveResult expr = Resolve(queryFromClause.Expression);
3372
if (queryFromClause.Type.IsNull) {
3373
v = MakeVariable(GetTypeForQueryVariable(expr.Type), queryFromClause.IdentifierToken);
3376
v = MakeVariable(ResolveType(queryFromClause.Type), queryFromClause.IdentifierToken);
3378
// resolve the .Cast<>() call
3379
ResolveResult methodGroup = resolver.ResolveMemberAccess(expr, "Cast", new[] { v.Type }, NameLookupMode.InvocationTarget);
3380
result = resolver.ResolveInvocation(methodGroup, new ResolveResult[0]);
3383
StoreCurrentState(queryFromClause.IdentifierToken);
3384
resolver = resolver.AddVariable(v);
3385
StoreResult(queryFromClause.IdentifierToken, new LocalResolveResult(v));
3387
if (currentQueryResult != null) {
3388
// this is a second 'from': resolve the .SelectMany() call
3389
QuerySelectClause selectClause = GetNextQueryClause(queryFromClause) as QuerySelectClause;
3390
ResolveResult selectResult;
3391
if (selectClause != null) {
3392
// from ... from ... select - the SelectMany call also performs the Select operation
3393
selectResult = Resolve(selectClause.Expression);
3395
// from .. from ... ... - introduce a transparent identifier
3396
selectResult = MakeTransparentIdentifierResolveResult();
3398
ResolveResult methodGroup = resolver.ResolveMemberAccess(currentQueryResult, "SelectMany", EmptyList<IType>.Instance, NameLookupMode.InvocationTarget);
3399
ResolveResult[] arguments = {
3400
new QueryExpressionLambda(1, result),
3401
new QueryExpressionLambda(2, selectResult)
3403
result = resolver.ResolveInvocation(methodGroup, arguments);
3406
return WrapResult(result);
3412
/// Wraps the result in an identity conversion.
3413
/// This is necessary so that '$from x in variable$ select x*2' does not resolve
3414
/// to the LocalResolveResult for the variable, which would confuse find references.
3416
ResolveResult WrapResult(ResolveResult result)
3418
return new ConversionResolveResult(result.Type, result, Conversion.IdentityConversion);
3421
ResolveResult IAstVisitor<ResolveResult>.VisitQueryContinuationClause(QueryContinuationClause queryContinuationClause)
3423
ResolveResult rr = Resolve(queryContinuationClause.PrecedingQuery);
3424
IType variableType = GetTypeForQueryVariable(rr.Type);
3425
StoreCurrentState(queryContinuationClause.IdentifierToken);
3426
IVariable v = MakeVariable(variableType, queryContinuationClause.IdentifierToken);
3427
resolver = resolver.AddVariable(v);
3428
StoreResult(queryContinuationClause.IdentifierToken, new LocalResolveResult(v));
3429
return WrapResult(rr);
3432
ResolveResult IAstVisitor<ResolveResult>.VisitQueryLetClause(QueryLetClause queryLetClause)
3434
ResolveResult expr = Resolve(queryLetClause.Expression);
3435
StoreCurrentState(queryLetClause.IdentifierToken);
3436
IVariable v = MakeVariable(expr.Type, queryLetClause.IdentifierToken);
3437
resolver = resolver.AddVariable(v);
3438
StoreResult(queryLetClause.IdentifierToken, new LocalResolveResult(v));
3439
if (currentQueryResult != null) {
3440
// resolve the .Select() call
3441
ResolveResult methodGroup = resolver.ResolveMemberAccess(currentQueryResult, "Select", EmptyList<IType>.Instance, NameLookupMode.InvocationTarget);
3442
ResolveResult[] arguments = { new QueryExpressionLambda(1, MakeTransparentIdentifierResolveResult()) };
3443
return resolver.ResolveInvocation(methodGroup, arguments);
3449
ResolveResult IAstVisitor<ResolveResult>.VisitQueryJoinClause(QueryJoinClause queryJoinClause)
3451
// join v in expr on onExpr equals equalsExpr [into g]
3452
ResolveResult inResult = null;
3453
ResolveResult expr = Resolve(queryJoinClause.InExpression);
3455
if (queryJoinClause.Type.IsNull) {
3456
variableType = GetTypeForQueryVariable(expr.Type);
3459
variableType = ResolveType(queryJoinClause.Type);
3461
// resolve the .Cast<>() call
3462
ResolveResult methodGroup = resolver.ResolveMemberAccess(expr, "Cast", new[] { variableType }, NameLookupMode.InvocationTarget);
3463
inResult = resolver.ResolveInvocation(methodGroup, new ResolveResult[0]);
3466
// resolve the 'On' expression in a context that contains only the previously existing range variables:
3467
// (before adding any variable)
3468
ResolveResult onResult = Resolve(queryJoinClause.OnExpression);
3470
// scan the 'Equals' expression in a context that contains only the variable 'v'
3471
CSharpResolver resolverOutsideQuery = resolver;
3472
resolverOutsideQuery = resolverOutsideQuery.PopBlock(); // pop all variables from the current query expression
3473
IVariable v = MakeVariable(variableType, queryJoinClause.JoinIdentifierToken);
3474
resolverOutsideQuery = resolverOutsideQuery.AddVariable(v);
3475
ResolveResult equalsResult = errorResult;
3476
ResetContext(resolverOutsideQuery, delegate {
3477
equalsResult = Resolve(queryJoinClause.EqualsExpression);
3479
StoreCurrentState(queryJoinClause.JoinIdentifierToken);
3480
StoreResult(queryJoinClause.JoinIdentifierToken, new LocalResolveResult(v));
3482
if (queryJoinClause.IsGroupJoin) {
3483
return ResolveGroupJoin(queryJoinClause, inResult, onResult, equalsResult);
3485
resolver = resolver.AddVariable(v);
3486
if (currentQueryResult != null) {
3487
QuerySelectClause selectClause = GetNextQueryClause(queryJoinClause) as QuerySelectClause;
3488
ResolveResult selectResult;
3489
if (selectClause != null) {
3490
// from ... join ... select - the Join call also performs the Select operation
3491
selectResult = Resolve(selectClause.Expression);
3493
// from .. join ... ... - introduce a transparent identifier
3494
selectResult = MakeTransparentIdentifierResolveResult();
3497
var methodGroup = resolver.ResolveMemberAccess(currentQueryResult, "Join", EmptyList<IType>.Instance);
3498
ResolveResult[] arguments = {
3500
new QueryExpressionLambda(1, onResult),
3501
new QueryExpressionLambda(1, equalsResult),
3502
new QueryExpressionLambda(2, selectResult)
3504
return resolver.ResolveInvocation(methodGroup, arguments);
3511
ResolveResult ResolveGroupJoin(QueryJoinClause queryJoinClause,
3512
ResolveResult inResult, ResolveResult onResult, ResolveResult equalsResult)
3514
Debug.Assert(queryJoinClause.IsGroupJoin);
3516
DomRegion intoIdentifierRegion = MakeRegion(queryJoinClause.IntoIdentifierToken);
3518
// We need to declare the group variable, but it's a bit tricky to determine its type:
3519
// We'll have to resolve the GroupJoin invocation and take a look at the inferred types
3520
// for the lambda given as last parameter.
3521
var methodGroup = resolver.ResolveMemberAccess(currentQueryResult, "GroupJoin", EmptyList<IType>.Instance);
3522
QuerySelectClause selectClause = GetNextQueryClause(queryJoinClause) as QuerySelectClause;
3523
LambdaResolveResult groupJoinLambda;
3524
if (selectClause != null) {
3525
// from ... join ... into g select - the GroupJoin call also performs the Select operation
3526
IParameter[] selectLambdaParameters = {
3527
new DefaultParameter(SpecialType.UnknownType, "<>transparentIdentifier"),
3528
new DefaultParameter(SpecialType.UnknownType, queryJoinClause.IntoIdentifier, region: intoIdentifierRegion)
3530
groupJoinLambda = new ImplicitlyTypedLambda(selectClause, selectLambdaParameters, this);
3532
// from .. join ... ... - introduce a transparent identifier
3533
groupJoinLambda = new QueryExpressionLambda(2, MakeTransparentIdentifierResolveResult());
3536
ResolveResult[] arguments = {
3538
new QueryExpressionLambda(1, onResult),
3539
new QueryExpressionLambda(1, equalsResult),
3542
ResolveResult rr = resolver.ResolveInvocation(methodGroup, arguments);
3543
InvocationResolveResult invocationRR = rr as InvocationResolveResult;
3545
IVariable groupVariable;
3546
if (groupJoinLambda is ImplicitlyTypedLambda) {
3547
var implicitlyTypedLambda = (ImplicitlyTypedLambda)groupJoinLambda;
3549
if (invocationRR != null && invocationRR.Arguments.Count > 0) {
3550
ConversionResolveResult crr = invocationRR.Arguments[invocationRR.Arguments.Count - 1] as ConversionResolveResult;
3552
ProcessConversion(null, crr.Input, crr.Conversion, crr.Type);
3555
implicitlyTypedLambda.EnforceMerge(this);
3556
if (implicitlyTypedLambda.Parameters.Count == 2) {
3557
StoreCurrentState(queryJoinClause.IntoIdentifierToken);
3558
groupVariable = implicitlyTypedLambda.Parameters[1];
3560
groupVariable = null;
3563
Debug.Assert(groupJoinLambda is QueryExpressionLambda);
3565
// Add the variable if the query expression continues after the group join
3566
// (there's no need to do this if there's only a select clause remaining, as
3567
// we already handled that in the ImplicitlyTypedLambda).
3569
// Get the inferred type of the group variable:
3570
IType[] inferredParameterTypes = null;
3571
if (invocationRR != null && invocationRR.Arguments.Count > 0) {
3572
ConversionResolveResult crr = invocationRR.Arguments[invocationRR.Arguments.Count - 1] as ConversionResolveResult;
3573
if (crr != null && crr.Conversion is QueryExpressionLambdaConversion) {
3574
inferredParameterTypes = ((QueryExpressionLambdaConversion)crr.Conversion).ParameterTypes;
3577
if (inferredParameterTypes == null)
3578
inferredParameterTypes = ((QueryExpressionLambda)groupJoinLambda).inferredParameterTypes;
3580
IType groupParameterType;
3581
if (inferredParameterTypes != null && inferredParameterTypes.Length == 2)
3582
groupParameterType = inferredParameterTypes[1];
3584
groupParameterType = SpecialType.UnknownType;
3586
StoreCurrentState(queryJoinClause.IntoIdentifierToken);
3587
groupVariable = MakeVariable(groupParameterType, queryJoinClause.IntoIdentifierToken);
3588
resolver = resolver.AddVariable(groupVariable);
3591
if (groupVariable != null) {
3592
StoreResult(queryJoinClause.IntoIdentifierToken, new LocalResolveResult(groupVariable));
3598
ResolveResult IAstVisitor<ResolveResult>.VisitQueryWhereClause(QueryWhereClause queryWhereClause)
3600
ResolveResult condition = Resolve(queryWhereClause.Condition);
3601
IType boolType = resolver.Compilation.FindType(KnownTypeCode.Boolean);
3602
Conversion conversionToBool = resolver.conversions.ImplicitConversion(condition, boolType);
3603
ProcessConversion(queryWhereClause.Condition, condition, conversionToBool, boolType);
3604
if (currentQueryResult != null) {
3605
if (conversionToBool != Conversion.IdentityConversion && conversionToBool != Conversion.None) {
3606
condition = new ConversionResolveResult(boolType, condition, conversionToBool);
3609
var methodGroup = resolver.ResolveMemberAccess(currentQueryResult, "Where", EmptyList<IType>.Instance);
3610
ResolveResult[] arguments = { new QueryExpressionLambda(1, condition) };
3611
return resolver.ResolveInvocation(methodGroup, arguments);
3617
ResolveResult IAstVisitor<ResolveResult>.VisitQuerySelectClause(QuerySelectClause querySelectClause)
3619
if (currentQueryResult == null) {
3620
ScanChildren(querySelectClause);
3623
QueryClause previousQueryClause = GetPreviousQueryClause(querySelectClause);
3624
// If the 'select' follows on a 'SelectMany', 'Join' or 'GroupJoin' clause, then the 'select' portion
3625
// was already done as part of the previous clause.
3626
if (((previousQueryClause is QueryFromClause && GetPreviousQueryClause(previousQueryClause) != null))
3627
|| previousQueryClause is QueryJoinClause)
3629
// GroupJoin already scans the following select clause in a different context,
3630
// so we must not scan it again.
3631
if (!(previousQueryClause is QueryJoinClause && ((QueryJoinClause)previousQueryClause).IsGroupJoin))
3632
Scan(querySelectClause.Expression);
3633
return WrapResult(currentQueryResult);
3636
QueryExpression query = querySelectClause.Parent as QueryExpression;
3637
string rangeVariable = GetSingleRangeVariable(query);
3638
if (rangeVariable != null) {
3639
IdentifierExpression ident = ParenthesizedExpression.UnpackParenthesizedExpression(querySelectClause.Expression) as IdentifierExpression;
3640
if (ident != null && ident.Identifier == rangeVariable && !ident.TypeArguments.Any()) {
3641
// selecting the single identifier that is the range variable
3642
if (query.Clauses.Count > 2) {
3643
// only if the query is not degenerate:
3644
// the Select call will be optimized away, so directly return the previous result
3645
Scan(querySelectClause.Expression);
3646
return WrapResult(currentQueryResult);
3651
ResolveResult expr = Resolve(querySelectClause.Expression);
3652
var methodGroup = resolver.ResolveMemberAccess(currentQueryResult, "Select", EmptyList<IType>.Instance);
3653
ResolveResult[] arguments = { new QueryExpressionLambda(1, expr) };
3654
return resolver.ResolveInvocation(methodGroup, arguments);
3658
/// Gets the name of the range variable in the specified query.
3659
/// If the query has multiple range variables, this method returns null.
3661
string GetSingleRangeVariable(QueryExpression query)
3665
foreach (QueryClause clause in query.Clauses.Skip(1)) {
3666
if (clause is QueryFromClause || clause is QueryJoinClause || clause is QueryLetClause) {
3667
// query has more than 1 range variable
3671
QueryFromClause fromClause = query.Clauses.FirstOrDefault() as QueryFromClause;
3672
if (fromClause != null)
3673
return fromClause.Identifier;
3674
QueryContinuationClause continuationClause = query.Clauses.FirstOrDefault() as QueryContinuationClause;
3675
if (continuationClause != null)
3676
return continuationClause.Identifier;
3680
ResolveResult IAstVisitor<ResolveResult>.VisitQueryGroupClause(QueryGroupClause queryGroupClause)
3682
if (currentQueryResult == null) {
3683
ScanChildren(queryGroupClause);
3687
// ... group projection by key
3688
ResolveResult projection = Resolve(queryGroupClause.Projection);
3689
ResolveResult key = Resolve(queryGroupClause.Key);
3691
var methodGroup = resolver.ResolveMemberAccess(currentQueryResult, "GroupBy", EmptyList<IType>.Instance);
3692
ResolveResult[] arguments = {
3693
new QueryExpressionLambda(1, key),
3694
new QueryExpressionLambda(1, projection)
3696
return resolver.ResolveInvocation(methodGroup, arguments);
3699
ResolveResult IAstVisitor<ResolveResult>.VisitQueryOrderClause(QueryOrderClause queryOrderClause)
3701
foreach (QueryOrdering ordering in queryOrderClause.Orderings) {
3702
currentQueryResult = Resolve(ordering);
3704
return WrapResult(currentQueryResult);
3707
ResolveResult IAstVisitor<ResolveResult>.VisitQueryOrdering(QueryOrdering queryOrdering)
3709
if (currentQueryResult == null) {
3710
ScanChildren(queryOrdering);
3713
// ... orderby sortKey [descending]
3714
ResolveResult sortKey = Resolve(queryOrdering.Expression);
3716
QueryOrderClause parentClause = queryOrdering.Parent as QueryOrderClause;
3717
bool isFirst = (parentClause == null || parentClause.Orderings.FirstOrDefault() == queryOrdering);
3718
string methodName = isFirst ? "OrderBy" : "ThenBy";
3719
if (queryOrdering.Direction == QueryOrderingDirection.Descending)
3720
methodName += "Descending";
3722
var methodGroup = resolver.ResolveMemberAccess(currentQueryResult, methodName, EmptyList<IType>.Instance);
3723
ResolveResult[] arguments = {
3724
new QueryExpressionLambda(1, sortKey),
3726
return resolver.ResolveInvocation(methodGroup, arguments);
3730
#region Constructor Initializer
3731
ResolveResult IAstVisitor<ResolveResult>.VisitConstructorInitializer(ConstructorInitializer constructorInitializer)
3733
if (!resolverEnabled) {
3734
ScanChildren(constructorInitializer);
3737
ResolveResult target;
3738
if (constructorInitializer.ConstructorInitializerType == ConstructorInitializerType.Base) {
3739
target = resolver.ResolveBaseReference();
3741
target = resolver.ResolveThisReference();
3743
string[] argumentNames;
3744
ResolveResult[] arguments = GetArguments(constructorInitializer.Arguments, out argumentNames);
3745
ResolveResult rr = resolver.ResolveObjectCreation(target.Type, arguments, argumentNames, allowProtectedAccess: true);
3746
ProcessConversionsInInvocation(null, constructorInitializer.Arguments, rr as CSharpInvocationResolveResult);
3753
ResolveResult IAstVisitor<ResolveResult>.VisitIdentifier(Identifier identifier)
3758
ResolveResult IAstVisitor<ResolveResult>.VisitComment (Comment comment)
3763
ResolveResult IAstVisitor<ResolveResult>.VisitNewLine (NewLineNode comment)
3768
ResolveResult IAstVisitor<ResolveResult>.VisitWhitespace(WhitespaceNode whitespaceNode)
3773
ResolveResult IAstVisitor<ResolveResult>.VisitText(TextNode textNode)
3778
ResolveResult IAstVisitor<ResolveResult>.VisitPreProcessorDirective (PreProcessorDirective preProcessorDirective)
3783
ResolveResult IAstVisitor<ResolveResult>.VisitCSharpTokenNode(CSharpTokenNode cSharpTokenNode)
3788
ResolveResult IAstVisitor<ResolveResult>.VisitArraySpecifier(ArraySpecifier arraySpecifier)
3793
ResolveResult IAstVisitor<ResolveResult>.VisitPatternPlaceholder(AstNode placeholder, ICSharpCode.NRefactory.PatternMatching.Pattern pattern)
3798
// Nodes where we just need to visit the children:
3799
ResolveResult IAstVisitor<ResolveResult>.VisitAccessor(Accessor accessor)
3801
ScanChildren(accessor);
3805
ResolveResult IAstVisitor<ResolveResult>.VisitSwitchSection(SwitchSection switchSection)
3807
ScanChildren(switchSection);
3811
ResolveResult IAstVisitor<ResolveResult>.VisitCaseLabel(CaseLabel caseLabel)
3813
ScanChildren(caseLabel);
3817
ResolveResult IAstVisitor<ResolveResult>.VisitConstraint(Constraint constraint)
3819
ScanChildren(constraint);
3824
#region Documentation Reference
3825
ResolveResult IAstVisitor<ResolveResult>.VisitDocumentationReference(DocumentationReference documentationReference)
3827
throw new NotImplementedException();