/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs
http://github.com/icsharpcode/ILSpy · C# · 4103 lines · 3399 code · 401 blank · 303 comment · 866 complexity · d765836f7b4dab83d4130dae6a772643 MD5 · raw file
Large files are truncated click here to view the full file
- // Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy of this
- // software and associated documentation files (the "Software"), to deal in the Software
- // without restriction, including without limitation the rights to use, copy, modify, merge,
- // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
- // to whom the Software is furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in all copies or
- // substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
- // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
- // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
- // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- // DEALINGS IN THE SOFTWARE.
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Linq;
- using System.Text;
- using System.Threading;
- using ICSharpCode.NRefactory.CSharp.Analysis;
- using ICSharpCode.NRefactory.CSharp.TypeSystem;
- using ICSharpCode.NRefactory.Semantics;
- using ICSharpCode.NRefactory.TypeSystem;
- using ICSharpCode.NRefactory.TypeSystem.Implementation;
- namespace ICSharpCode.NRefactory.CSharp.Resolver
- {
- /// <summary>
- /// Traverses the DOM and resolves expressions.
- /// </summary>
- /// <remarks>
- /// The ResolveVisitor does two jobs at the same time: it tracks the resolve context (properties on CSharpResolver)
- /// and it resolves the expressions visited.
- /// To allow using the context tracking without having to resolve every expression in the file (e.g. when you want to resolve
- /// only a single node deep within the DOM), you can use the <see cref="IResolveVisitorNavigator"/> interface.
- /// The navigator allows you to switch the between scanning mode and resolving mode.
- /// In scanning mode, the context is tracked (local variables registered etc.), but nodes are not resolved.
- /// While scanning, the navigator will get asked about every node that the resolve visitor is about to enter.
- /// This allows the navigator whether to keep scanning, whether switch to resolving mode, or whether to completely skip the
- /// subtree rooted at that node.
- ///
- /// In resolving mode, the context is tracked and nodes will be resolved.
- /// The resolve visitor may decide that it needs to resolve other nodes as well in order to resolve the current node.
- /// In this case, those nodes will be resolved automatically, without asking the navigator interface.
- /// For child nodes that are not essential to resolving, the resolve visitor will switch back to scanning mode (and thus will
- /// ask the navigator for further instructions).
- ///
- /// Moreover, there is the <c>ResolveAll</c> mode - it works similar to resolving mode, but will not switch back to scanning mode.
- /// The whole subtree will be resolved without notifying the navigator.
- /// </remarks>
- sealed class ResolveVisitor : IAstVisitor<ResolveResult>
- {
- // The ResolveVisitor is also responsible for handling lambda expressions.
-
- static readonly ResolveResult errorResult = ErrorResolveResult.UnknownError;
-
- CSharpResolver resolver;
- /// <summary>Resolve result of the current LINQ query.</summary>
- /// <remarks>We do not have to put this into the stored state (resolver) because
- /// query expressions are always resolved in a single operation.</remarks>
- ResolveResult currentQueryResult;
- readonly CSharpUnresolvedFile unresolvedFile;
- readonly Dictionary<AstNode, ResolveResult> resolveResultCache = new Dictionary<AstNode, ResolveResult>();
- readonly Dictionary<AstNode, CSharpResolver> resolverBeforeDict = new Dictionary<AstNode, CSharpResolver>();
- readonly Dictionary<AstNode, CSharpResolver> resolverAfterDict = new Dictionary<AstNode, CSharpResolver>();
- readonly Dictionary<Expression, ConversionWithTargetType> conversionDict = new Dictionary<Expression, ConversionWithTargetType>();
-
- internal struct ConversionWithTargetType
- {
- public readonly Conversion Conversion;
- public readonly IType TargetType;
-
- public ConversionWithTargetType(Conversion conversion, IType targetType)
- {
- this.Conversion = conversion;
- this.TargetType = targetType;
- }
- }
-
- IResolveVisitorNavigator navigator;
- bool resolverEnabled;
- List<LambdaBase> undecidedLambdas;
- internal CancellationToken cancellationToken;
-
- #region Constructor
- static readonly IResolveVisitorNavigator skipAllNavigator = new ConstantModeResolveVisitorNavigator(ResolveVisitorNavigationMode.Skip, null);
-
- /// <summary>
- /// Creates a new ResolveVisitor instance.
- /// </summary>
- public ResolveVisitor(CSharpResolver resolver, CSharpUnresolvedFile unresolvedFile)
- {
- if (resolver == null)
- throw new ArgumentNullException("resolver");
- this.resolver = resolver;
- this.unresolvedFile = unresolvedFile;
- this.navigator = skipAllNavigator;
- }
-
- internal void SetNavigator(IResolveVisitorNavigator navigator)
- {
- this.navigator = navigator ?? skipAllNavigator;
- }
-
- ResolveResult voidResult {
- get {
- return new ResolveResult(resolver.Compilation.FindType(KnownTypeCode.Void));
- }
- }
- #endregion
-
- #region ResetContext
- /// <summary>
- /// Resets the visitor to the stored position, runs the action, and then reverts the visitor to the previous position.
- /// </summary>
- void ResetContext(CSharpResolver storedContext, Action action)
- {
- var oldResolverEnabled = this.resolverEnabled;
- var oldResolver = this.resolver;
- var oldQueryResult = this.currentQueryResult;
- try {
- this.resolverEnabled = false;
- this.resolver = storedContext;
- this.currentQueryResult = null;
-
- action();
- } finally {
- this.resolverEnabled = oldResolverEnabled;
- this.resolver = oldResolver;
- this.currentQueryResult = oldQueryResult;
- }
- }
- #endregion
-
- #region Scan / Resolve
- /// <summary>
- /// Scans the AST rooted at the given node.
- /// </summary>
- public void Scan(AstNode node)
- {
- if (node == null || node.IsNull)
- return;
- switch (node.NodeType) {
- case NodeType.Token:
- case NodeType.Whitespace:
- return; // skip tokens, identifiers, comments, etc.
- }
- // don't Scan again if the node was already resolved
- if (resolveResultCache.ContainsKey(node)) {
- // Restore state change caused by this node:
- CSharpResolver newResolver;
- if (resolverAfterDict.TryGetValue(node, out newResolver))
- resolver = newResolver;
- return;
- }
-
- var mode = navigator.Scan(node);
- switch (mode) {
- case ResolveVisitorNavigationMode.Skip:
- if (node is VariableDeclarationStatement || node is SwitchSection) {
- // Enforce scanning of variable declarations.
- goto case ResolveVisitorNavigationMode.Scan;
- }
- StoreCurrentState(node);
- break;
- case ResolveVisitorNavigationMode.Scan:
- bool oldResolverEnabled = resolverEnabled;
- var oldResolver = resolver;
- resolverEnabled = false;
- StoreCurrentState(node);
- ResolveResult result = node.AcceptVisitor(this);
- if (result != null) {
- // If the node was resolved, store the result even though it wasn't requested.
- // This is necessary so that Visit-methods that decide to always resolve are
- // guaranteed to get called only once.
- // This is used for lambda registration.
- StoreResult(node, result);
- if (resolver != oldResolver) {
- // The node changed the resolver state:
- resolverAfterDict.Add(node, resolver);
- }
- cancellationToken.ThrowIfCancellationRequested();
- }
- resolverEnabled = oldResolverEnabled;
- break;
- case ResolveVisitorNavigationMode.Resolve:
- Resolve(node);
- break;
- default:
- throw new InvalidOperationException("Invalid value for ResolveVisitorNavigationMode");
- }
- }
-
- /// <summary>
- /// Equivalent to 'Scan', but also resolves the node at the same time.
- /// This method should be only used if the CSharpResolver passed to the ResolveVisitor was manually set
- /// to the correct state.
- /// Otherwise, use <c>resolver.Scan(syntaxTree); var result = resolver.GetResolveResult(node);</c>
- /// instead.
- /// --
- /// This method now is internal, because it is difficult to use correctly.
- /// Users of the public API should use Scan()+GetResolveResult() instead.
- /// </summary>
- internal ResolveResult Resolve(AstNode node)
- {
- if (node == null || node.IsNull)
- return errorResult;
- bool oldResolverEnabled = resolverEnabled;
- resolverEnabled = true;
- ResolveResult result;
- if (!resolveResultCache.TryGetValue(node, out result)) {
- cancellationToken.ThrowIfCancellationRequested();
- StoreCurrentState(node);
- var oldResolver = resolver;
- result = node.AcceptVisitor(this) ?? errorResult;
- StoreResult(node, result);
- if (resolver != oldResolver) {
- // The node changed the resolver state:
- resolverAfterDict.Add(node, resolver);
- }
- }
- resolverEnabled = oldResolverEnabled;
- return result;
- }
-
- IType ResolveType(AstType type)
- {
- return Resolve(type).Type;
- }
-
- void StoreCurrentState(AstNode node)
- {
- // It's possible that we re-visit an expression that we scanned over earlier,
- // so we might have to overwrite an existing state.
-
- #if DEBUG
- CSharpResolver oldResolver;
- if (resolverBeforeDict.TryGetValue(node, out oldResolver)) {
- Debug.Assert(oldResolver.LocalVariables.SequenceEqual(resolver.LocalVariables));
- }
- #endif
-
- resolverBeforeDict[node] = resolver;
- }
-
- void StoreResult(AstNode node, ResolveResult result)
- {
- Debug.Assert(result != null);
- if (node.IsNull)
- return;
- Log.WriteLine("Resolved '{0}' to {1}", node, result);
- Debug.Assert(!CSharpAstResolver.IsUnresolvableNode(node));
- // The state should be stored before the result is.
- Debug.Assert(resolverBeforeDict.ContainsKey(node));
- // Don't store results twice.
- Debug.Assert(!resolveResultCache.ContainsKey(node));
- // Don't use ConversionResolveResult as a result, because it can get
- // confused with an implicit conversion.
- Debug.Assert(!(result is ConversionResolveResult) || result is CastResolveResult);
- resolveResultCache[node] = result;
- if (navigator != null)
- navigator.Resolved(node, result);
- }
-
- void ScanChildren(AstNode node)
- {
- for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) {
- Scan(child);
- }
- }
- #endregion
-
- #region Process Conversions
- sealed class AnonymousFunctionConversion : Conversion
- {
- public readonly IType ReturnType;
- public readonly ExplicitlyTypedLambda ExplicitlyTypedLambda;
- public readonly LambdaTypeHypothesis Hypothesis;
- readonly bool isValid;
-
- public AnonymousFunctionConversion(IType returnType, LambdaTypeHypothesis hypothesis, bool isValid)
- {
- if (returnType == null)
- throw new ArgumentNullException("returnType");
- this.ReturnType = returnType;
- this.Hypothesis = hypothesis;
- this.isValid = isValid;
- }
-
- public AnonymousFunctionConversion(IType returnType, ExplicitlyTypedLambda explicitlyTypedLambda, bool isValid)
- {
- if (returnType == null)
- throw new ArgumentNullException("returnType");
- this.ReturnType = returnType;
- this.ExplicitlyTypedLambda = explicitlyTypedLambda;
- this.isValid = isValid;
- }
-
- public override bool IsValid {
- get { return isValid; }
- }
-
- public override bool IsImplicit {
- get { return true; }
- }
-
- public override bool IsAnonymousFunctionConversion {
- get { return true; }
- }
- }
-
- /// <summary>
- /// Convert 'rr' to the target type using the specified conversion.
- /// </summary>
- void ProcessConversion(Expression expr, ResolveResult rr, Conversion conversion, IType targetType)
- {
- AnonymousFunctionConversion afc = conversion as AnonymousFunctionConversion;
- if (afc != null) {
- Log.WriteLine("Processing conversion of anonymous function to " + targetType + "...");
-
- Log.Indent();
- if (afc.Hypothesis != null)
- afc.Hypothesis.MergeInto(this, afc.ReturnType);
- if (afc.ExplicitlyTypedLambda != null)
- afc.ExplicitlyTypedLambda.ApplyReturnType(this, afc.ReturnType);
- Log.Unindent();
- }
- if (expr != null && !expr.IsNull && conversion != Conversion.IdentityConversion) {
- navigator.ProcessConversion(expr, rr, conversion, targetType);
- conversionDict[expr] = new ConversionWithTargetType(conversion, targetType);
- }
- }
-
- void ImportConversions(ResolveVisitor childVisitor)
- {
- foreach (var pair in childVisitor.conversionDict) {
- conversionDict.Add(pair.Key, pair.Value);
- navigator.ProcessConversion(pair.Key, resolveResultCache[pair.Key], pair.Value.Conversion, pair.Value.TargetType);
- }
- }
-
- /// <summary>
- /// Convert 'rr' to the target type.
- /// </summary>
- void ProcessConversion(Expression expr, ResolveResult rr, IType targetType)
- {
- if (expr == null || expr.IsNull)
- return;
- ProcessConversion(expr, rr, resolver.conversions.ImplicitConversion(rr, targetType), targetType);
- }
-
- /// <summary>
- /// Resolves the specified expression and processes the conversion to targetType.
- /// </summary>
- void ResolveAndProcessConversion(Expression expr, IType targetType)
- {
- if (targetType.Kind == TypeKind.Unknown) {
- // no need to resolve the expression right now
- Scan(expr);
- } else {
- ProcessConversion(expr, Resolve(expr), targetType);
- }
- }
-
- void ProcessConversionResult(Expression expr, ConversionResolveResult rr)
- {
- if (rr != null && !(rr is CastResolveResult))
- ProcessConversion(expr, rr.Input, rr.Conversion, rr.Type);
- }
-
- void ProcessConversionResults(IEnumerable<Expression> expr, IEnumerable<ResolveResult> conversionResolveResults)
- {
- Debug.Assert(expr.Count() == conversionResolveResults.Count());
- using (var e1 = expr.GetEnumerator()) {
- using (var e2 = conversionResolveResults.GetEnumerator()) {
- while (e1.MoveNext() && e2.MoveNext()) {
- ProcessConversionResult(e1.Current, e2.Current as ConversionResolveResult);
- }
- }
- }
- }
-
- void MarkUnknownNamedArguments(IEnumerable<Expression> arguments)
- {
- foreach (var nae in arguments.OfType<NamedArgumentExpression>()) {
- StoreCurrentState(nae);
- StoreResult(nae, new NamedArgumentResolveResult(nae.Name, resolveResultCache[nae.Expression]));
- }
- }
-
- void ProcessInvocationResult(Expression target, IEnumerable<Expression> arguments, ResolveResult invocation)
- {
- if (invocation is CSharpInvocationResolveResult || invocation is DynamicInvocationResolveResult) {
- int i = 0;
- IList<ResolveResult> argumentsRR;
- if (invocation is CSharpInvocationResolveResult) {
- var csi = (CSharpInvocationResolveResult)invocation;
- if (csi.IsExtensionMethodInvocation) {
- Debug.Assert(arguments.Count() + 1 == csi.Arguments.Count);
- ProcessConversionResult(target, csi.Arguments[0] as ConversionResolveResult);
- i = 1;
- } else {
- Debug.Assert(arguments.Count() == csi.Arguments.Count);
- }
- argumentsRR = csi.Arguments;
- }
- else {
- argumentsRR = ((DynamicInvocationResolveResult)invocation).Arguments;
- }
- foreach (Expression arg in arguments) {
- ResolveResult argRR = argumentsRR[i++];
- NamedArgumentExpression nae = arg as NamedArgumentExpression;
- NamedArgumentResolveResult nrr = argRR as NamedArgumentResolveResult;
- Debug.Assert((nae == null) == (nrr == null));
- if (nae != null && nrr != null) {
- StoreCurrentState(nae);
- StoreResult(nae, nrr);
- ProcessConversionResult(nae.Expression, nrr.Argument as ConversionResolveResult);
- } else {
- ProcessConversionResult(arg, argRR as ConversionResolveResult);
- }
- }
- }
- else {
- MarkUnknownNamedArguments(arguments);
- }
- }
- #endregion
-
- #region GetResolveResult
- /// <summary>
- /// Gets the resolve result for the specified node.
- /// If the node was not resolved by the navigator, this method will resolve it.
- /// </summary>
- public ResolveResult GetResolveResult(AstNode node)
- {
- Debug.Assert(!CSharpAstResolver.IsUnresolvableNode(node));
-
- MergeUndecidedLambdas();
- ResolveResult result;
- if (resolveResultCache.TryGetValue(node, out result))
- return result;
-
- AstNode parent;
- CSharpResolver storedResolver = GetPreviouslyScannedContext(node, out parent);
- ResetContext(
- storedResolver,
- delegate {
- navigator = new NodeListResolveVisitorNavigator(node);
- Debug.Assert(!resolverEnabled);
- Scan(parent);
- navigator = skipAllNavigator;
- });
-
- MergeUndecidedLambdas();
- return resolveResultCache[node];
- }
-
- CSharpResolver GetPreviouslyScannedContext(AstNode node, out AstNode parent)
- {
- parent = node;
- CSharpResolver storedResolver;
- while (!resolverBeforeDict.TryGetValue(parent, out storedResolver)) {
- AstNode tmp = parent.Parent;
- if (tmp == null)
- 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?");
- if (tmp.NodeType == NodeType.Whitespace)
- return resolver; // special case: resolve expression within preprocessor directive
- parent = tmp;
- }
- return storedResolver;
- }
-
- /// <summary>
- /// Gets the resolver state in front of the specified node.
- /// If the node was not visited by a previous scanning process, the
- /// AST will be scanned again to determine the state.
- /// </summary>
- public CSharpResolver GetResolverStateBefore(AstNode node)
- {
- MergeUndecidedLambdas();
- CSharpResolver r;
- if (resolverBeforeDict.TryGetValue(node, out r))
- return r;
-
- AstNode parent;
- CSharpResolver storedResolver = GetPreviouslyScannedContext(node, out parent);
- ResetContext(
- storedResolver,
- delegate {
- navigator = new NodeListResolveVisitorNavigator(new[] { node }, scanOnly: true);
- Debug.Assert(!resolverEnabled);
- // parent might already be resolved if 'node' is an unresolvable node
- Scan(parent);
- navigator = skipAllNavigator;
- });
-
- MergeUndecidedLambdas();
- while (node != null) {
- if (resolverBeforeDict.TryGetValue(node, out r))
- return r;
- node = node.Parent;
- }
- return null;
- }
-
- public CSharpResolver GetResolverStateAfter(AstNode node)
- {
- // Resolve the node to fill the resolverAfterDict
- GetResolveResult(node);
- CSharpResolver result;
- if (resolverAfterDict.TryGetValue(node, out result))
- return result;
- else
- return GetResolverStateBefore(node);
- }
-
- public ConversionWithTargetType GetConversionWithTargetType(Expression expr)
- {
- GetResolverStateBefore(expr);
- ResolveParentForConversion(expr);
- ConversionWithTargetType result;
- if (conversionDict.TryGetValue(expr, out result)) {
- return result;
- } else {
- ResolveResult rr = GetResolveResult(expr);
- return new ConversionWithTargetType(Conversion.IdentityConversion, rr.Type);
- }
- }
- #endregion
-
- #region Track UsingScope
- ResolveResult IAstVisitor<ResolveResult>.VisitSyntaxTree(SyntaxTree unit)
- {
- CSharpResolver previousResolver = resolver;
- try {
- if (unresolvedFile != null) {
- resolver = resolver.WithCurrentUsingScope(unresolvedFile.RootUsingScope.Resolve(resolver.Compilation));
- } else {
- var cv = new TypeSystemConvertVisitor(unit.FileName ?? string.Empty);
- ApplyVisitorToUsings(cv, unit.Children);
- PushUsingScope(cv.UnresolvedFile.RootUsingScope);
- }
- ScanChildren(unit);
- return voidResult;
- } finally {
- resolver = previousResolver;
- }
- }
-
- void ApplyVisitorToUsings(TypeSystemConvertVisitor visitor, IEnumerable<AstNode> children)
- {
- foreach (var child in children) {
- if (child is ExternAliasDeclaration || child is UsingDeclaration || child is UsingAliasDeclaration) {
- child.AcceptVisitor(visitor);
- }
- }
- }
-
- void PushUsingScope(UsingScope usingScope)
- {
- usingScope.Freeze();
- resolver = resolver.WithCurrentUsingScope(new ResolvedUsingScope(resolver.CurrentTypeResolveContext, usingScope));
- }
- ResolveResult IAstVisitor<ResolveResult>.VisitNamespaceDeclaration(NamespaceDeclaration namespaceDeclaration)
- {
- CSharpResolver previousResolver = resolver;
- try {
- var nsName = namespaceDeclaration.NamespaceName;
- AstNode child = namespaceDeclaration.FirstChild;
- for (; child != null && child.Role != Roles.LBrace; child = child.NextSibling) {
- Scan(child);
- }
- if (unresolvedFile != null) {
- resolver = resolver.WithCurrentUsingScope(unresolvedFile.GetUsingScope(namespaceDeclaration.StartLocation).Resolve(resolver.Compilation));
- } else {
- // string fileName = namespaceDeclaration.GetRegion().FileName ?? string.Empty;
- // Fetch parent using scope
- // Create root using scope if necessary
- if (resolver.CurrentUsingScope == null)
- PushUsingScope(new UsingScope());
-
- // Create child using scope
- DomRegion region = namespaceDeclaration.GetRegion();
- var identifiers = namespaceDeclaration.Identifiers.ToList();
- // For all but the last identifier:
- UsingScope usingScope;
- for (int i = 0; i < identifiers.Count - 1; i++) {
- usingScope = new UsingScope(resolver.CurrentUsingScope.UnresolvedUsingScope, identifiers[i]);
- usingScope.Region = region;
- PushUsingScope(usingScope);
- }
- // Last using scope:
- usingScope = new UsingScope(resolver.CurrentUsingScope.UnresolvedUsingScope, identifiers.Last());
- usingScope.Region = region;
- var cv = new TypeSystemConvertVisitor(new CSharpUnresolvedFile(), usingScope);
- ApplyVisitorToUsings(cv, namespaceDeclaration.Children);
- PushUsingScope(usingScope);
- }
- for (; child != null; child = child.NextSibling) {
- Scan(child);
- }
- // merge undecided lambdas before leaving the using scope so that
- // the resolver can make better use of its cache
- MergeUndecidedLambdas();
- if (resolver.CurrentUsingScope != null && resolver.CurrentUsingScope.Namespace != null)
- return new NamespaceResolveResult(resolver.CurrentUsingScope.Namespace);
- else
- return null;
- } finally {
- resolver = previousResolver;
- }
- }
- #endregion
-
- #region Track CurrentTypeDefinition
- ResolveResult VisitTypeOrDelegate(AstNode typeDeclaration, string name, int typeParameterCount)
- {
- CSharpResolver previousResolver = resolver;
- try {
- ITypeDefinition newTypeDefinition = null;
- if (resolver.CurrentTypeDefinition != null) {
- int totalTypeParameterCount = resolver.CurrentTypeDefinition.TypeParameterCount + typeParameterCount;
- foreach (ITypeDefinition nestedType in resolver.CurrentTypeDefinition.NestedTypes) {
- if (nestedType.Name == name && nestedType.TypeParameterCount == totalTypeParameterCount) {
- newTypeDefinition = nestedType;
- break;
- }
- }
- } else if (resolver.CurrentUsingScope != null) {
- newTypeDefinition = resolver.CurrentUsingScope.Namespace.GetTypeDefinition(name, typeParameterCount);
- }
- if (newTypeDefinition != null)
- resolver = resolver.WithCurrentTypeDefinition(newTypeDefinition);
-
- ScanChildren(typeDeclaration);
-
- // merge undecided lambdas before leaving the type definition so that
- // the resolver can make better use of its cache
- MergeUndecidedLambdas();
-
- return newTypeDefinition != null ? new TypeResolveResult(newTypeDefinition) : errorResult;
- } finally {
- resolver = previousResolver;
- }
- }
-
- ResolveResult IAstVisitor<ResolveResult>.VisitTypeDeclaration(TypeDeclaration typeDeclaration)
- {
- return VisitTypeOrDelegate(typeDeclaration, typeDeclaration.Name, typeDeclaration.TypeParameters.Count);
- }
-
- ResolveResult IAstVisitor<ResolveResult>.VisitDelegateDeclaration(DelegateDeclaration delegateDeclaration)
- {
- return VisitTypeOrDelegate(delegateDeclaration, delegateDeclaration.Name, delegateDeclaration.TypeParameters.Count);
- }
- #endregion
-
- #region Track CurrentMember
- ResolveResult IAstVisitor<ResolveResult>.VisitFieldDeclaration(FieldDeclaration fieldDeclaration)
- {
- return VisitFieldOrEventDeclaration(fieldDeclaration, SymbolKind.Field);
- }
-
- ResolveResult IAstVisitor<ResolveResult>.VisitFixedFieldDeclaration(FixedFieldDeclaration fixedFieldDeclaration)
- {
- return VisitFieldOrEventDeclaration(fixedFieldDeclaration, SymbolKind.Field);
- }
-
- ResolveResult IAstVisitor<ResolveResult>.VisitEventDeclaration(EventDeclaration eventDeclaration)
- {
- return VisitFieldOrEventDeclaration(eventDeclaration, SymbolKind.Event);
- }
-
- ResolveResult VisitFieldOrEventDeclaration(EntityDeclaration fieldOrEventDeclaration, SymbolKind symbolKind)
- {
- //int initializerCount = fieldOrEventDeclaration.GetChildrenByRole(Roles.Variable).Count;
- CSharpResolver oldResolver = resolver;
- for (AstNode node = fieldOrEventDeclaration.FirstChild; node != null; node = node.NextSibling) {
- if (node.Role == Roles.Variable || node.Role == FixedFieldDeclaration.VariableRole) {
- IMember member;
- if (unresolvedFile != null) {
- member = GetMemberFromLocation(node);
- } else {
- string name = ((VariableInitializer)node).Name;
- member = AbstractUnresolvedMember.Resolve(resolver.CurrentTypeResolveContext, symbolKind, name);
- }
- resolver = resolver.WithCurrentMember(member);
-
- Scan(node);
-
- resolver = oldResolver;
- } else {
- Scan(node);
- }
- }
- return voidResult;
- }
-
- IMember GetMemberFromLocation(AstNode node)
- {
- ITypeDefinition typeDef = resolver.CurrentTypeDefinition;
- if (typeDef == null)
- return null;
- TextLocation location = TypeSystemConvertVisitor.GetStartLocationAfterAttributes(node);
- return typeDef.GetMembers(
- delegate (IUnresolvedMember m) {
- if (m.UnresolvedFile != unresolvedFile)
- return false;
- DomRegion region = m.Region;
- return !region.IsEmpty && region.Begin <= location && region.End > location;
- },
- GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions
- ).FirstOrDefault();
- }
-
- ResolveResult IAstVisitor<ResolveResult>.VisitVariableInitializer(VariableInitializer variableInitializer)
- {
- // Within the variable initializer, the newly declared variable is not yet available:
- var resolverWithVariable = resolver;
- if (variableInitializer.Parent is VariableDeclarationStatement)
- resolver = resolver.PopLastVariable();
-
- ArrayInitializerExpression aie = variableInitializer.Initializer as ArrayInitializerExpression;
- if (resolverEnabled || aie != null) {
- ResolveResult result = errorResult;
- if (variableInitializer.Parent is FieldDeclaration || variableInitializer.Parent is EventDeclaration) {
- if (resolver.CurrentMember != null) {
- result = new MemberResolveResult(null, resolver.CurrentMember, false);
- }
- } else {
- string identifier = variableInitializer.Name;
- foreach (IVariable v in resolverWithVariable.LocalVariables) {
- if (v.Name == identifier) {
- result = new LocalResolveResult(v);
- break;
- }
- }
- }
- ArrayType arrayType = result.Type as ArrayType;
- if (aie != null && arrayType != null) {
- StoreCurrentState(aie);
- List<Expression> initializerElements = new List<Expression>();
- int[] sizes = new int[arrayType.Dimensions];
- UnpackArrayInitializer(initializerElements, sizes, aie, 0, true);
- ResolveResult[] initializerElementResults = new ResolveResult[initializerElements.Count];
- for (int i = 0; i < initializerElementResults.Length; i++) {
- initializerElementResults[i] = Resolve(initializerElements[i]);
- }
- var arrayCreation = resolver.ResolveArrayCreation(arrayType.ElementType, sizes, initializerElementResults);
- StoreResult(aie, arrayCreation);
- ProcessConversionResults(initializerElements, arrayCreation.InitializerElements);
- } else if (variableInitializer.Parent is FixedStatement) {
- var initRR = Resolve(variableInitializer.Initializer);
- PointerType pointerType;
- if (initRR.Type.Kind == TypeKind.Array) {
- pointerType = new PointerType(((ArrayType)initRR.Type).ElementType);
- } else if (ReflectionHelper.GetTypeCode(initRR.Type) == TypeCode.String) {
- pointerType = new PointerType(resolver.Compilation.FindType(KnownTypeCode.Char));
- } else {
- pointerType = null;
- ProcessConversion(variableInitializer.Initializer, initRR, result.Type);
- }
- if (pointerType != null) {
- var conversion = resolver.conversions.ImplicitConversion(pointerType, result.Type);
- if (conversion.IsIdentityConversion)
- conversion = Conversion.ImplicitPointerConversion;
- ProcessConversion(variableInitializer.Initializer, initRR, conversion, result.Type);
- }
- } else {
- ResolveAndProcessConversion(variableInitializer.Initializer, result.Type);
- }
- resolver = resolverWithVariable;
- return result;
- } else {
- Scan(variableInitializer.Initializer);
- resolver = resolverWithVariable;
- return null;
- }
- }
-
- ResolveResult IAstVisitor<ResolveResult>.VisitFixedVariableInitializer(FixedVariableInitializer fixedVariableInitializer)
- {
- if (resolverEnabled) {
- ResolveResult result = errorResult;
- if (resolver.CurrentMember != null) {
- result = new MemberResolveResult(null, resolver.CurrentMember, false);
- }
- ResolveAndProcessConversion(fixedVariableInitializer.CountExpression, resolver.Compilation.FindType(KnownTypeCode.Int32));
- return result;
- } else {
- ScanChildren(fixedVariableInitializer);
- return null;
- }
- }
-
- ResolveResult VisitMethodMember(EntityDeclaration memberDeclaration)
- {
- CSharpResolver oldResolver = resolver;
- try {
- IMember member = null;
- if (unresolvedFile != null) {
- member = GetMemberFromLocation(memberDeclaration);
- }
- if (member == null) {
- // Re-discover the method:
- SymbolKind symbolKind = memberDeclaration.SymbolKind;
- var parameterTypes = TypeSystemConvertVisitor.GetParameterTypes(memberDeclaration.GetChildrenByRole(Roles.Parameter), InterningProvider.Dummy);
- if (symbolKind == SymbolKind.Constructor) {
- string name = memberDeclaration.HasModifier(Modifiers.Static) ? ".cctor" : ".ctor";
- member = AbstractUnresolvedMember.Resolve(
- resolver.CurrentTypeResolveContext, symbolKind, name,
- parameterTypeReferences: parameterTypes);
- } else if (symbolKind == SymbolKind.Destructor) {
- member = AbstractUnresolvedMember.Resolve(resolver.CurrentTypeResolveContext, symbolKind, "Finalize");
- } else {
- string[] typeParameterNames = memberDeclaration.GetChildrenByRole(Roles.TypeParameter).Select(tp => tp.Name).ToArray();
- AstType explicitInterfaceAstType = memberDeclaration.GetChildByRole(EntityDeclaration.PrivateImplementationTypeRole);
- ITypeReference explicitInterfaceType = null;
- if (!explicitInterfaceAstType.IsNull) {
- explicitInterfaceType = explicitInterfaceAstType.ToTypeReference();
- }
- member = AbstractUnresolvedMember.Resolve(
- resolver.CurrentTypeResolveContext, symbolKind, memberDeclaration.Name,
- explicitInterfaceType, typeParameterNames, parameterTypes);
- }
- }
- resolver = resolver.WithCurrentMember(member);
- ScanChildren(memberDeclaration);
-
- if (member != null)
- return new MemberResolveResult(null, member, false);
- else
- return errorResult;
- } finally {
- resolver = oldResolver;
- }
- }
-
- ResolveResult IAstVisitor<ResolveResult>.VisitMethodDeclaration(MethodDeclaration methodDeclaration)
- {
- return VisitMethodMember(methodDeclaration);
- }
-
- ResolveResult IAstVisitor<ResolveResult>.VisitOperatorDeclaration(OperatorDeclaration operatorDeclaration)
- {
- return VisitMethodMember(operatorDeclaration);
- }
-
- ResolveResult IAstVisitor<ResolveResult>.VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration)
- {
- return VisitMethodMember(constructorDeclaration);
- }
-
- ResolveResult IAstVisitor<ResolveResult>.VisitDestructorDeclaration(DestructorDeclaration destructorDeclaration)
- {
- return VisitMethodMember(destructorDeclaration);
- }
-
- // handle properties/indexers
- ResolveResult VisitPropertyMember(EntityDeclaration propertyOrIndexerDeclaration)
- {
- CSharpResolver oldResolver = resolver;
- try {
- IMember member;
- if (unresolvedFile != null) {
- member = GetMemberFromLocation(propertyOrIndexerDeclaration);
- } else {
- // Re-discover the property:
- string name = propertyOrIndexerDeclaration.Name;
- var parameterTypeReferences = TypeSystemConvertVisitor.GetParameterTypes(propertyOrIndexerDeclaration.GetChildrenByRole(Roles.Parameter), InterningProvider.Dummy);
- AstType explicitInterfaceAstType = propertyOrIndexerDeclaration.GetChildByRole(EntityDeclaration.PrivateImplementationTypeRole);
- ITypeReference explicitInterfaceType = null;
- if (!explicitInterfaceAstType.IsNull) {
- explicitInterfaceType = explicitInterfaceAstType.ToTypeReference();
- }
- member = AbstractUnresolvedMember.Resolve(
- resolver.CurrentTypeResolveContext, propertyOrIndexerDeclaration.SymbolKind, name,
- explicitInterfaceType, parameterTypeReferences: parameterTypeReferences);
- }
- // We need to use the property as current member so that indexer parameters can be resolved correctly.
- resolver = resolver.WithCurrentMember(member);
- var resolverWithPropertyAsMember = resolver;
-
- for (AstNode node = propertyOrIndexerDeclaration.FirstChild; node != null; node = node.NextSibling) {
- if (node.Role == PropertyDeclaration.GetterRole && member is IProperty) {
- resolver = resolver.WithCurrentMember(((IProperty)member).Getter);
- Scan(node);
- resolver = resolverWithPropertyAsMember;
- } else if (node.Role == PropertyDeclaration.SetterRole && member is IProperty) {
- resolver = resolver.WithCurrentMember(((IProperty)member).Setter);
- Scan(node);
- resolver = resolverWithPropertyAsMember;
- } else {
- Scan(node);
- }
- }
- if (member != null)
- return new MemberResolveResult(null, member, false);
- else
- return errorResult;
- } finally {
- resolver = oldResolver;
- }
- }
-
- ResolveResult IAstVisitor<ResolveResult>.VisitPropertyDeclaration(PropertyDeclaration propertyDeclaration)
- {
- return VisitPropertyMember(propertyDeclaration);
- }
-
- ResolveResult IAstVisitor<ResolveResult>.VisitIndexerDeclaration(IndexerDeclaration indexerDeclaration)
- {
- return VisitPropertyMember(indexerDeclaration);
- }
-
- ResolveResult IAstVisitor<ResolveResult>.VisitCustomEventDeclaration(CustomEventDeclaration eventDeclaration)
- {
- CSharpResolver oldResolver = resolver;
- try {
- IMember member;
- if (unresolvedFile != null) {
- member = GetMemberFromLocation(eventDeclaration);
- } else {
- string name = eventDeclaration.Name;
- AstType explicitInterfaceAstType = eventDeclaration.PrivateImplementationType;
- if (explicitInterfaceAstType.IsNull) {
- member = AbstractUnresolvedMember.Resolve(resolver.CurrentTypeResolveContext, SymbolKind.Event, name);
- } else {
- member = AbstractUnresolvedMember.Resolve(resolver.CurrentTypeResolveContext, SymbolKind.Event, name,
- explicitInterfaceAstType.ToTypeReference());
- }
- }
- resolver = resolver.WithCurrentMember(member);
- var resolverWithEventAsMember = resolver;
-
- for (AstNode node = eventDeclaration.FirstChild; node != null; node = node.NextSibling) {
- if (node.Role == CustomEventDeclaration.AddAccessorRole && member is IEvent) {
- resolver = resolver.WithCurrentMember(((IEvent)member).AddAccessor);
- Scan(node);
- resolver = resolverWithEventAsMember;
- } else if (node.Role == CustomEventDeclaration.RemoveAccessorRole && member is IEvent) {
- resolver = resolver.WithCurrentMember(((IEvent)member).RemoveAccessor);
- Scan(node);
- resolver = resolverWithEventAsMember;
- } else {
- Scan(node);
- }
- }
- if (member != null)
- return new MemberResolveResult(null, member, false);
- else
- return errorResult;
- } finally {
- resolver = oldResolver;
- }
- }
-
- ResolveResult IAstVisitor<ResolveResult>.VisitParameterDeclaration(ParameterDeclaration parameterDeclaration)
- {
- ScanChildren(parameterDeclaration);
- if (resolverEnabled) {
- string name = parameterDeclaration.Name;
-
- if (parameterDeclaration.Parent is DocumentationReference) {
- // create a dummy parameter
- IType type = ResolveType(parameterDeclaration.Type);
- switch (parameterDeclaration.ParameterModifier) {
- case ParameterModifier.Ref:
- case ParameterModifier.Out:
- type = new ByReferenceType(type);
- break;
- }
- return new LocalResolveResult(new DefaultParameter(
- type, name,
- isRef: parameterDeclaration.ParameterModifier == ParameterModifier.Ref,
- isOut: parameterDeclaration.ParameterModifier == ParameterModifier.Out,
- isParams: parameterDeclaration.ParameterModifier == ParameterModifier.Params));
- }
-
- // Look in lambda parameters:
- foreach (IParameter p in resolver.LocalVariables.OfType<IParameter>()) {
- if (p.Name == name)
- return new LocalResolveResult(p);
- }
-
- IParameterizedMember pm = resolver.CurrentMember as IParameterizedMember;
- if (pm == null && resolver.CurrentTypeDefinition != null) {
- // Also consider delegate parameters:
- pm = resolver.CurrentTypeDefinition.GetDelegateInvokeMethod();
- // pm will be null if the current type isn't a delegate
- }
- if (pm != null) {
- foreach (IParameter p in pm.Parameters) {
- if (p.Name == name) {
- return new LocalResolveResult(p);
- }
- }
- }
-
- return errorResult;
- } else {
- return null;
- }
- }
-
- ResolveResult IAstVisitor<ResolveResult>.VisitTypeParameterDeclaration(TypeParameterDeclaration typeParameterDeclaration)
- {
- ScanChildren(typeParameterDeclaration);
- if (resolverEnabled) {
- string name = typeParameterDeclaration.Name;
- IMethod m = resolver.CurrentMember as IMethod;
- if (m != null) {
- foreach (var tp in m.TypeParameters) {
- if (tp.Name == name)
- return new TypeResolveResult(tp);
- }
- }
- if (resolver.CurrentTypeDefinition != null) {
- var typeParameters = resolver.CurrentTypeDefinition.TypeParameters;
- // look backwards so that TPs in the current type take precedence over those copied from outer types
- for (int i = typeParameters.Count - 1; i >= 0; i--) {
- if (typeParameters[i].Name == name)
- return new TypeResolveResult(typeParameters[i]);
- }
- }
- return errorResult;
- } else {
- return null;
- }
- }
-
- ResolveResult IAstVisitor<ResolveResult>.VisitEnumMemberDeclaration(EnumMemberDeclaration enumMemberDeclaration)
- {
- CSharpResolver oldResolver = resolver;
- try {
- // Scan enum member attributes before setting resolver.CurrentMember, so that
- // enum values used as attribute arguments have the correct type.
- // (within an enum member, all other enum members are treated as having their underlying type)
- foreach (var attributeSection in enumMemberDeclaration.Attributes)
- Scan(attributeSection);
-
- IMember member = null;
- if (unresolvedFile != null) {
- member = GetMemberFromLocation(enumMemberDeclaration);
- } else if (resolver.CurrentTypeDefinition != null) {
- string name = enumMemberDeclaration.Name;
- member = resolver.CurrentTypeDefinition.GetFields(f => f.Name == name, GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault();
- }
- resolver = resolver.WithCurrentMember(member);
-
- if (resolverEnabled && resolver.CurrentTypeDefinition != null) {
- ResolveAndProcessConversion(enumMemberDeclaration.Initializer, resolver.CurrentTypeDefinition.EnumUnderlyingType);
- if (resolverEnabled && member != null)
- return new MemberResolveResult(null, member, false);
- else
- return errorResult;
- } else {
- Scan(enumMemberDeclaration.Initializer);
- return null;
- }
- } finally {
- resolver = oldResolver;
- }
- }
- #endregion
-
- #region Track CheckForOverflow
- ResolveResult IAstVisitor<ResolveResult>.VisitCheckedExpression(CheckedExpression checkedExpression)
- {
- CSharpResolver oldResolver = resolver;
- try {
- resolver = resolver.WithCheckForOverflow(true);
- if (resolverEnabled) {
- return Resolve(checkedExpression.Expression);
- } else {
- ScanChildren(checkedExpression);
- return null;
- }
- } finally {
- resolver = oldResolver;
- }
- }
-
- ResolveResult IAstVisitor<ResolveResult>.VisitUncheckedExpression(UncheckedExpression uncheckedExpression)
- {
- CSharpResolver oldResolver = resolver;
- try {
- resolver = resolver.WithCheckForOverflow(false);
- if (resolverEnabled) {
- return Resolve(uncheckedExpression.Expression);
- } else {
- ScanChildren(uncheckedExpression);
- return null;
- }
- } finally {
- resolver = oldResolver;
- }
- }
-
- ResolveResult IAstVisitor<ResolveResult>.VisitCheckedStatement(CheckedStatement checkedStatement)
- {
- CSharpResolver oldResolver = resolver;
- try {
- resolver = resolver.WithCheckForOverflow(true);
- ScanChildren(checkedStatement);
- return voidResult;
- } finally {
- resolver = oldResolver;
- }
- }
-
- ResolveResult IAstVisitor<ResolveResult>.VisitUncheckedStatement(UncheckedStatement uncheckedStatement)
- {
- CSharpResolver oldResolver = resolver;
- try {
- resolver = resolver.WithCheckForOverflow(false);
- ScanChildren(uncheckedStatement);
- return voidResult;
- } finally {
- resolver = oldResolver;
- }
- }
- #endregion
-
- #region Visit AnonymousTypeCreateExpression
- static string GetAnonymousTypePropertyName(Expression expr, out Expression resolveExpr)
- {
- if (expr is NamedExpression) {
- var namedArgExpr = (NamedExpression)expr;
- resolveExpr = namedArgExpr.Expression;
- return namedArgExpr.Name;
- }
- // no name given, so it's a projection initializer
- if (expr is MemberReferenceExpression) {
- resolveExpr = expr;
- return ((MemberReferenceExpression)expr).MemberName;
- }
- if (expr is IdentifierExpression) {
- resolveExpr = expr;
- return ((IdentifierExpression)expr).Identifier;
- }
- resolveExpr = null;
- return null;
- }
-
- class AnonymousTypeMember
- {
- public readonly Expression Expression;
- public readonly ResolveResult Initializer;
-
- public AnonymousTypeMember(Expression expression, ResolveResult initializer)
- {
- this.Expression = expression;
- this.Initializer = initializer;
- }
- }
-
- ResolveResult IAstVisitor<ResolveResult>.VisitAnonymousTypeCreateExpression(AnonymousTypeCreateExpression anonymousTypeCreateExpression)
- {
- // 7.6.10.6 Anonymous object creation expressions
- List<IUnresolvedProperty> unresolvedProperties = new List<IUnresolvedProperty>();
- List<AnonymousTypeMember> members = new List<AnonymousTypeMember>();
- foreach (var expr in anonymousTypeCreateExpression.Initializers) {
- Expression resolveExpr;
- var name = GetAnonymousTypePropertyName(expr, out resolveExpr);
- if (resolveExpr != null) {
- var initRR = Resolve(resolveExpr);
- var returnTypeRef = initRR.Type.ToTypeReference();
- var property = new DefaultUnresolvedProperty();
- property.Name = name;
- property.Accessibility = Accessibility.Public;
- property.ReturnType = returnTypeRef;
- property.Getter = new DefaultUnresolvedMethod {
- Name = "get_" + name,
- Accessibility = Accessibility.Public,
- ReturnType = returnTypeRef,
- SymbolKind = SymbolKind.Accessor,
- AccessorOwner = property
- };
- unresolvedProperties.Add(property);
- members.Add(new AnonymousTypeMember(expr, initRR));
- } else {
- Scan(expr);
- }
- }
- var anonymousType = new AnonymousType(resolver.Compilation, unresolvedProperties);
- var properties = anonymousType.GetProperties().ToList();
- Debug.Assert(properties.Count == members.Count);
- List<ResolveResult> assignments = new List<ResolveResult>();
- for (int i = 0; i < members.Count; i++) {
- ResolveResult lhs = new MemberResolveResult(new InitializedObjectResolveResult(anonymousType), properties[i]);
- ResolveResult rhs = members[i].Initializer;
- ResolveResult assignment = resolver.ResolveAssignment(AssignmentOperatorType.Assign, lhs, rhs);
- var ne = members[i].Expression as NamedExpression;
- if (ne != null) {
- StoreCurrentState(ne);
- // ne.Expression was already resolved by the first loop
- StoreResult(ne, lhs);
- }
- assignments.Add(assignment);
- }
- var anonymousCtor = DefaultResolvedMethod.GetDummyConstructor(resolver.Compilation, anonymousType);
- return new InvocationResolveResult(null, anonymousCtor, initializerStatements: assignments);
- }
- #endregion
-
- #region Visit Expressions
- ResolveResult IAstVisitor<ResolveResult>.VisitArrayCreateExpression(ArrayCreateExpression arrayCreateExpression)
- {
- int dimensions = arrayCreateExpression.Arguments.Count;
- IEnumerable<Expression> sizeArgumentExpressions;
- ResolveResult[] sizeArguments;
- IEnumerable<ArraySpecifier> additionalArraySpecifiers;
- if (dimensions == 0) {
- var firstSpecifier = arrayCreateExpression.AdditionalArraySpecifiers.FirstOrDefault();
- if (firstSpecifier != null) {
- dimensions = firstSpecifier.Dimensions;
- additionalArraySpecifiers = arrayCreateExpression.AdditionalArraySpecifiers.Skip(1);
- } else {
- // No array specifiers (neither with nor without size) - can happen if there are syntax errors.
- // Dimensions must be at least one; otherwise 'new ArrayType' will crash.
- dimensions = 1;
- additionalArraySpecifiers = arrayCreateExpression.AdditionalArraySpecifiers;
- }
- sizeArguments = null;
- sizeArgumentExpressions = null;
- } else {
- sizeArgumentExpressions = arrayCreateExpression.Arguments;
- sizeArguments = new ResolveResult[dimensions];
- int pos = 0;
- foreach (var node in sizeArgumentExpressions)
- sizeArguments[pos++] = Resolve(node);
- additionalArraySpecifiers = arrayCreateExpression.AdditionalArraySpecifiers;
- }
-
- int[] sizes;
- List<Expression> initializerElements;
- ResolveResult[] initializerElementResults;
- if (arrayCreateExpression.Initializer.IsNull) {
- sizes = null;
- initializerElements = null;
- initializerElementResults = null;
- } else {
- StoreCurrentState(arrayCreateExpression.Initializer);
-
- initializerElements = new List<Expression>();
- sizes = new int[dimensions];
- UnpackArrayInitializer(initializerElements, sizes, arrayCreateExpression.Initializer, 0, true);
- initializerElementResults = new ResolveResult[initializerElements.Count];
- for (int i = 0; i < initializerElementResults.Length; i++) {
- initializerElementResults[i] = Resolve(initializerElements[i]);
- }
- StoreResult(arrayCreateExpression.Initializer, voidResult);
- }
-
- IType elementType;
- if (arrayCreateExpression.Type.IsNull) {
- elementType = null;
- } else {
- elementType = ResolveType(arrayCreateExpression.Type);
- foreach (var spec in additionalArraySpecifiers.Reverse()) {
- elementType = new ArrayType(resolver.Compilation, elementType, spec.Dimensions);
- }
- }
- ArrayCreateResolveResult acrr;
- if (sizeArguments != null) {
- acrr = resolver.ResolveArrayCreation(elementType, sizeArguments, initializerElementResults);
- } else if (sizes != null) {
- acrr = resolver.ResolveArrayCreation(elementType, sizes, initializerElementResults);
- } else {
- // neither size arguments nor an initializer exist -> error
- return new ErrorResolveResult(new ArrayType(resolver.Compilation, elementType ?? SpecialType.UnknownType, dimensions));
- }
- if (sizeArgumentExpressions != null)
- ProcessConversionResults(sizeArgumentExpressions, acrr.SizeArguments);
- if (acrr.InitializerElements != null)
- ProcessConversionResults(initializerElements, acrr.InitializerElements);
- return acrr;
- }
-
- void UnpackArrayInitializer(List<Expression> elementList, int[] sizes, ArrayInitializerExpression initializer, int dimension, bool resolveNestedInitializersToVoid)
- {
- Debug.Assert(dimension < sizes.Length);
- int elementCount = 0;
- if (dimension + 1 < sizes.Length) {
- foreach (var node in initializer.Elements) {
- ArrayInitializerExpression aie = node as ArrayInitializerExpression;
- if (aie != null) {
- if (resolveNestedInitializersToVoid) {
- StoreCurrentState(aie);
- StoreResult(aie, voidResult);
- }
- UnpackArrayInitializer(elementList, sizes, aie, dimension + 1, resolveNestedInitializersToVoid);
- } else {
- elementList.Add(node);
- }
- elementCount++;
- }
- } else {
- foreach (var expr in initializer.Elements) {
- elementList.Add(expr);
- elementCount++;
- }
- }
- if (sizes[dimension] == 0) // 0 = uninitialized
- sizes[dimension] = elementCount;
- else if (sizes[dimension] != elementCount)
- sizes[dimension] = -1; // -1 = error
- }
-
- ResolveResult IAstVisitor<ResolveResult>.VisitArrayInitializerExpression(ArrayInitializerExpression arrayInitializerExpression)
- {
- // Array initializers are handled by their parent expression.
- ScanChildren(arrayInitializerExpression);
- return errorResult;
- }
-
- ResolveResult IAstVisitor<ResolveResult>.VisitAsExpression(AsExpression asExpression)
- {
- if (resolverEnabled) {
- ResolveResult input = Resolve(asExpression.Exp…