Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1325)

Unified Diff: pkg/analyzer/lib/src/generated/resolver.dart

Issue 2456803004: fixes #27586, prefer context type in generic inference (Closed)
Patch Set: fix Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/analyzer/lib/src/error/codes.dart ('k') | pkg/analyzer/lib/src/generated/static_type_analyzer.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/analyzer/lib/src/generated/resolver.dart
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 95c01cbcf58ac482327c1e2ea1887585f371fca2..a1979d0bd6e23cc4c9ad322a8f35d55da564924a 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -19,6 +19,7 @@ import 'package:analyzer/exception/exception.dart';
import 'package:analyzer/src/dart/ast/ast.dart';
import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/member.dart' show ConstructorMember;
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/resolver/inheritance_manager.dart';
import 'package:analyzer/src/dart/resolver/scope.dart';
@@ -649,8 +650,9 @@ class BestPracticesVerifier extends RecursiveAstVisitor<Object> {
} else if (displayName == FunctionElement.CALL_METHOD_NAME &&
node is MethodInvocation &&
node.staticInvokeType is InterfaceType) {
- displayName =
- "${resolutionMap.staticInvokeTypeForInvocationExpression(node).displayName}.${element.displayName}";
+ displayName = "${resolutionMap
+ .staticInvokeTypeForInvocationExpression(node)
+ .displayName}.${element.displayName}";
}
_errorReporter.reportErrorForNode(
HintCode.DEPRECATED_MEMBER_USE, node, [displayName]);
@@ -4169,35 +4171,6 @@ class InferenceContext {
}
/**
- * Like [getContext] but expands a union type into a list of types.
- */
- Iterable<DartType> getTypes(AstNode node) {
- DartType t = getContext(node);
- if (t == null) {
- return DartType.EMPTY_LIST;
- }
- if (t is InterfaceType && t.isDartAsyncFutureOr) {
- var tArg = t.typeArguments[0]; // The T in FutureOr<T>
- return [
- _typeProvider.futureType.instantiate([tArg]),
- tArg
- ];
- }
- return [t];
- }
-
- /**
- * Match type [t1] against type [t2] as follows.
- * If `t1 = I<dynamic, ..., dynamic>`, then look for a supertype
- * of t1 of the form `K<S0, ..., Sm>` where `t2 = K<S0', ..., Sm'>`
- * If the supertype exists, use the constraints `S0 <: S0', ... Sm <: Sm'`
- * to derive a concrete instantation for I of the form `<T0, ..., Tn>`,
- * such that `I<T0, .., Tn> <: t2`
- */
- List<DartType> matchTypes(DartType t1, DartType t2) =>
- (t1 is InterfaceType && t2 is InterfaceType) ? _matchTypes(t1, t2) : null;
-
- /**
* Pop a return type off of the return stack.
*
* Also record any inferred return type using [setType], unless this node
@@ -4248,113 +4221,6 @@ class InferenceContext {
_errorReporter.reportErrorForNode(error, node, [node, type]);
}
- List<DartType> _matchTypes(InterfaceType t1, InterfaceType t2) {
- if (t1 == t2) {
- return t2.typeArguments;
- }
- List<DartType> tArgs1 = t1.typeArguments;
- List<DartType> tArgs2 = t2.typeArguments;
- // If t1 isn't a raw type, bail out
- if (tArgs1 != null && tArgs1.any((t) => !t.isDynamic)) {
- return null;
- }
-
- // This is our inferred type argument list. We start at all dynamic,
- // and fill in with inferred types when we reach a match.
- List<DartType> actuals =
- new List<DartType>.filled(tArgs1.length, _typeProvider.dynamicType);
-
- // When we find the supertype of t1 with the same
- // classname as t2 (see below), we have the following:
- // If t1 is an instantiation of a class T1<X0, ..., Xn>
- // and t2 is an instantiation of a class T2<Y0, ...., Ym>
- // of the form t2 = T2<S0, ..., Sm>
- // then we want to choose instantiations for the Xi
- // T0, ..., Tn such that T1<T0, ..., Tn> <: t2 .
- // To find this, we simply instantate T1 with
- // X0, ..., Xn, and then find its superclass
- // T2<T0', ..., Tn'>. We then solve the constraint
- // set T0' <: S0, ..., Tn' <: Sn for the Xi.
- // Currently, we only handle constraints where
- // the Ti' is one of the Xi'. If there are multiple
- // constraints on some Xi, we choose the lower of the
- // two (if it exists).
- bool permute(List<DartType> permutedArgs) {
- if (permutedArgs == null) {
- return false;
- }
- List<TypeParameterElement> ps = t1.typeParameters;
- List<DartType> ts = ps.map((p) => p.type).toList();
- for (int i = 0; i < permutedArgs.length; i++) {
- DartType tVar = permutedArgs[i];
- DartType tActual = tArgs2[i];
- int index = ts.indexOf(tVar);
- if (index >= 0 && _typeSystem.isSubtypeOf(tActual, actuals[index])) {
- actuals[index] = tActual;
- }
- }
- return actuals.any((x) => !x.isDynamic);
- }
-
- // Look for the first supertype of t1 with the same class name as t2.
- bool match(InterfaceType t1, Set<Element> visited) {
- if (t1.element == t2.element) {
- return permute(t1.typeArguments);
- }
-
- if (t1 == _typeProvider.objectType) {
- return false;
- }
-
- Element element = t1.element;
- if (visited == null) {
- visited = new HashSet<Element>();
- }
- if (element == null || !visited.add(element)) {
- return false;
- }
- try {
- if (match(t1.superclass, visited)) {
- return true;
- }
-
- List<InterfaceType> mixins = t1.mixins;
- int mixinLength = mixins.length;
- for (int i = 0; i < mixinLength; i++) {
- if (match(mixins[i], visited)) {
- return true;
- }
- }
-
- List<InterfaceType> interfaces = t1.interfaces;
- int interfaceLength = interfaces.length;
- for (int j = 0; j < interfaceLength; j++) {
- if (match(interfaces[j], visited)) {
- return true;
- }
- }
- } finally {
- visited.remove(element);
- }
- return false;
- }
-
- // We have that t1 = T1<dynamic, ..., dynamic>.
- // To match t1 against t2, we use the uninstantiated version
- // of t1, essentially treating it as an instantiation with
- // fresh variables, and solve for the variables.
- // t1.element.type will be of the form T1<X0, ..., Xn>
- if (!match(t1.element.type, null)) {
- return null;
- }
- DartType newT1 = t1.element.type.instantiate(actuals);
- // If we found a solution, return it.
- if (_typeSystem.isSubtypeOf(newT1, t2)) {
- return actuals;
- }
- return null;
- }
-
/**
* Clear the type information assocated with [node].
*/
@@ -4363,31 +4229,18 @@ class InferenceContext {
}
/**
- * Look for contextual type information attached to [node]. Returns
- * the type if found, otherwise null.
+ * Look for contextual type information attached to [node], and returns
+ * the type if found.
*
- * If [node] has a contextual union type like `T | Future<T>` this will be
- * returned. You can use [getType] if you prefer to only get the `T`.
+ * The returned type may be partially or completely unknown, denoted with an
+ * unknown type `?`, for example `List<?>` or `(?, int) -> void`.
+ * You can use [StrongTypeSystemImpl.upperBoundForType] or
+ * [StrongTypeSystemImpl.lowerBoundForType] if you would prefer a known type
+ * that represents the bound of the context type.
*/
static DartType getContext(AstNode node) => node?.getProperty(_typeProperty);
/**
- * Look for a single contextual type attached to [node], and returns the type
- * if found, otherwise null.
- *
- * If [node] has a contextual union type like `T | Future<T>` this will
- * simplify it to only return `T`. If the caller can handle a union type,
- * [getContext] should be used instead.
- */
- static DartType getType(AstNode node) {
- DartType t = getContext(node);
- if (t is InterfaceType && t.isDartAsyncFutureOr) {
- return t.typeArguments[0]; // The T in FutureOr<T>
- }
- return t;
- }
-
- /**
* Attach contextual type information [type] to [node] for use during
* inference.
*/
@@ -4509,7 +4362,8 @@ class InstanceFieldResolverVisitor extends ResolverVisitor {
typeAnalyzer.thisType = enclosingClass?.type;
if (enclosingClass == null) {
AnalysisEngine.instance.logger.logInformation(
- "Missing element for class declaration ${node.name.name} in ${definingLibrary.source.fullName}",
+ "Missing element for class declaration ${node.name
+ .name} in ${definingLibrary.source.fullName}",
new CaughtException(new AnalysisException(), null));
// Don't try to re-resolve the initializers if we cannot set up the
// right name scope for resolution.
@@ -5456,7 +5310,7 @@ class ResolverVisitor extends ScopedVisitor {
@override
Object visitArgumentList(ArgumentList node) {
- DartType callerType = InferenceContext.getType(node);
+ DartType callerType = InferenceContext.getContext(node);
if (callerType is FunctionType) {
Map<String, DartType> namedParameterTypes =
callerType.namedParameterTypes;
@@ -6069,8 +5923,9 @@ class ResolverVisitor extends ScopedVisitor {
_enclosingFunction = node.element;
_overrideManager.enterScope();
try {
- DartType functionType = InferenceContext.getType(node);
- if (functionType is FunctionType) {
+ DartType functionType = InferenceContext.getContext(node);
+ var ts = typeSystem;
+ if (functionType is FunctionType && ts is StrongTypeSystemImpl) {
functionType =
matchFunctionTypeParameters(node.typeParameters, functionType);
if (functionType is FunctionType) {
@@ -6088,8 +5943,7 @@ class ResolverVisitor extends ScopedVisitor {
// missing in old code.
if (futureThenType.parameters.isNotEmpty) {
if (!futureThenType.parameters[0].type.isDartAsyncFutureOr) {
- var typeParamS =
- futureThenType.returnType.flattenFutures(typeSystem);
+ var typeParamS = futureThenType.returnType.flattenFutures(ts);
returnType = _createFutureOr(typeParamS);
}
}
@@ -6113,7 +5967,7 @@ class ResolverVisitor extends ScopedVisitor {
Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
node.function?.accept(this);
node.accept(elementResolver);
- _inferArgumentTypesFromContext(node);
+ _inferArgumentTypesForInvocation(node);
node.argumentList?.accept(this);
node.accept(typeAnalyzer);
return null;
@@ -6211,56 +6065,8 @@ class ResolverVisitor extends ScopedVisitor {
@override
Object visitInstanceCreationExpression(InstanceCreationExpression node) {
- TypeName classTypeName = node.constructorName.type;
- // TODO(leafp): Currently, we may re-infer types here, since we
- // sometimes resolve multiple times. We should really check that we
- // have not already inferred something. However, the obvious ways to
- // check this don't work, since we may have been instantiated
- // to bounds in an earlier phase, and we *do* want to do inference
- // in that case.
- if (classTypeName.typeArguments == null) {
- // Given a union of context types ` T0 | T1 | ... | Tn`, find the first
- // valid instantiation `new C<Ti>`, if it exists.
- // TODO(jmesserly): if we support union types for real, `new C<Ti | Tj>`
- // will become a valid possibility. Right now the only allowed union is
- // `T | Future<T>` so we can take a simple approach.
- for (var contextType in inferenceContext.getTypes(node)) {
- if (contextType is InterfaceType &&
- contextType.typeArguments != null &&
- contextType.typeArguments.isNotEmpty) {
- // TODO(jmesserly): for generic methods we use the
- // StrongTypeSystemImpl.inferGenericFunctionCall, which appears to
- // be a tad more powerful than matchTypes.
- //
- // For example it can infer this case:
- //
- // class E<S, T> extends A<C<S>, T> { ... }
- // A<C<int>, String> a0 = /*infer<int, String>*/new E("hello");
- //
- // See _inferArgumentTypesFromContext in this file for use of it.
- List<DartType> targs =
- inferenceContext.matchTypes(classTypeName.type, contextType);
- if (targs != null && targs.any((t) => !t.isDynamic)) {
- ClassElement classElement =
- resolutionMap.typeForTypeName(classTypeName).element;
- InterfaceType rawType = classElement.type;
- InterfaceType fullType =
- rawType.substitute2(targs, rawType.typeArguments);
- // The element resolver uses the type on the constructor name, so
- // infer it first
- typeAnalyzer.inferConstructorName(node.constructorName, fullType);
- break;
- }
- }
- }
- }
node.constructorName?.accept(this);
- FunctionType constructorType = resolutionMap
- .staticElementForConstructorReference(node.constructorName)
- ?.type;
- if (constructorType != null) {
- InferenceContext.setType(node.argumentList, constructorType);
- }
+ _inferArgumentTypesForInstanceCreate(node);
node.argumentList?.accept(this);
node.accept(elementResolver);
node.accept(typeAnalyzer);
@@ -6275,18 +6081,18 @@ class ResolverVisitor extends ScopedVisitor {
@override
Object visitListLiteral(ListLiteral node) {
- DartType contextType = InferenceContext.getType(node);
- List<DartType> targs = null;
+ InterfaceType listT;
+
if (node.typeArguments != null) {
- targs = node.typeArguments.arguments.map((t) => t.type).toList();
- } else if (contextType is InterfaceType) {
- InterfaceType listD =
- typeProvider.listType.instantiate([typeProvider.dynamicType]);
- targs = inferenceContext.matchTypes(listD, contextType);
- }
- if (targs != null && targs.length == 1 && !targs[0].isDynamic) {
- DartType eType = targs[0];
- InterfaceType listT = typeProvider.listType.instantiate([eType]);
+ var targs = node.typeArguments.arguments.map((t) => t.type).toList();
+ if (targs.length == 1 && !targs[0].isDynamic) {
+ listT = typeProvider.listType.instantiate([targs[0]]);
+ }
+ } else if (strongMode) {
+ listT = typeAnalyzer.inferListType(node, downwards: true);
+ }
+ if (listT != null) {
+ DartType eType = listT.typeArguments[0];
for (Expression child in node.elements) {
InferenceContext.setType(child, eType);
}
@@ -6300,19 +6106,18 @@ class ResolverVisitor extends ScopedVisitor {
@override
Object visitMapLiteral(MapLiteral node) {
- DartType contextType = InferenceContext.getType(node);
- List<DartType> targs = null;
+ InterfaceType mapT;
if (node.typeArguments != null) {
- targs = node.typeArguments.arguments.map((t) => t.type).toList();
- } else if (contextType is InterfaceType) {
- InterfaceType mapD = typeProvider.mapType
- .instantiate([typeProvider.dynamicType, typeProvider.dynamicType]);
- targs = inferenceContext.matchTypes(mapD, contextType);
- }
- if (targs != null && targs.length == 2 && targs.any((t) => !t.isDynamic)) {
- DartType kType = targs[0];
- DartType vType = targs[1];
- InterfaceType mapT = typeProvider.mapType.instantiate([kType, vType]);
+ var targs = node.typeArguments.arguments.map((t) => t.type).toList();
+ if (targs.length == 2 && targs.any((t) => !t.isDynamic)) {
+ mapT = typeProvider.mapType.instantiate([targs[0], targs[1]]);
+ }
+ } else if (strongMode) {
+ mapT = typeAnalyzer.inferMapType(node, downwards: true);
+ }
+ if (mapT != null) {
+ DartType kType = mapT.typeArguments[0];
+ DartType vType = mapT.typeArguments[1];
for (MapLiteralEntry entry in node.entries) {
InferenceContext.setType(entry.key, kType);
InferenceContext.setType(entry.value, vType);
@@ -6358,7 +6163,7 @@ class ResolverVisitor extends ScopedVisitor {
node.target?.accept(this);
node.typeArguments?.accept(this);
node.accept(elementResolver);
- _inferArgumentTypesFromContext(node);
+ _inferArgumentTypesForInvocation(node);
node.argumentList?.accept(this);
node.accept(typeAnalyzer);
return null;
@@ -6651,12 +6456,13 @@ class ResolverVisitor extends ScopedVisitor {
// If it's sync* we expect Iterable<T>
// If it's async* we expect Stream<T>
InterfaceType rawType = isAsynchronous
- ? typeProvider.streamDynamicType
- : typeProvider.iterableDynamicType;
+ ? typeProvider.streamType
+ : typeProvider.iterableType;
// Match the types to instantiate the type arguments if possible
- List<DartType> typeArgs =
- inferenceContext.matchTypes(rawType, declaredType);
- return (typeArgs?.length == 1) ? typeArgs[0] : null;
+ List<DartType> targs = declaredType.typeArguments;
+ if (targs.length == 1 && rawType.instantiate(targs) == declaredType) {
+ return targs[0];
+ }
}
// async functions expect `Future<T> | T`
var futureTypeParam = declaredType.flattenFutures(typeSystem);
@@ -6755,33 +6561,99 @@ class ResolverVisitor extends ScopedVisitor {
return false;
}
- void _inferArgumentTypesFromContext(InvocationExpression node) {
- if (!strongMode) {
- // Use propagated type inference for lambdas if not in strong mode.
- _inferFunctionExpressionsParametersTypes(node.argumentList);
+ FunctionType _inferArgumentTypesForGeneric(AstNode inferenceNode,
+ DartType uninstantiatedType, TypeArgumentList typeArguments,
+ {AstNode errorNode}) {
+ errorNode ??= inferenceNode;
+ TypeSystem ts = typeSystem;
+ if (typeArguments == null &&
+ uninstantiatedType is FunctionType &&
+ uninstantiatedType.typeFormals.isNotEmpty &&
+ ts is StrongTypeSystemImpl) {
+ return ts.inferGenericFunctionOrType/*<FunctionType>*/(
+ uninstantiatedType,
+ ParameterElement.EMPTY_LIST,
+ DartType.EMPTY_LIST,
+ InferenceContext.getContext(inferenceNode),
+ downwards: true,
+ errorReporter: errorReporter,
+ errorNode: errorNode);
+ }
+ return null;
+ }
+
+ void _inferArgumentTypesForInstanceCreate(InstanceCreationExpression node) {
+ ConstructorName constructor = node.constructorName;
+ TypeName classTypeName = constructor?.type;
+ if (classTypeName == null || !strongMode) {
return;
}
- DartType contextType = node.staticInvokeType;
- if (contextType is FunctionType) {
- DartType originalType = node.function.staticType;
- DartType returnContextType = InferenceContext.getContext(node);
- TypeSystem ts = typeSystem;
- if (returnContextType != null &&
- node.typeArguments == null &&
- originalType is FunctionType &&
- originalType.typeFormals.isNotEmpty &&
- ts is StrongTypeSystemImpl) {
- contextType = ts.inferGenericFunctionCall(
- originalType,
- DartType.EMPTY_LIST,
- DartType.EMPTY_LIST,
- originalType.returnType,
- returnContextType);
+ ConstructorElement originalElement =
+ resolutionMap.staticElementForConstructorReference(constructor);
+ FunctionType inferred;
+ // If the constructor is generic, we'll have a ConstructorMember that
+ // substitutes in type arguments (possibly `dynamic`) from earlier in
+ // resolution.
+ //
+ // Otherwise we'll have a ConstructorElement, and we can skip inference
+ // because there's nothing to infer in a non-generic type.
+ if (classTypeName.typeArguments == null &&
+ originalElement is ConstructorMember) {
+ // TODO(leafp): Currently, we may re-infer types here, since we
+ // sometimes resolve multiple times. We should really check that we
+ // have not already inferred something. However, the obvious ways to
+ // check this don't work, since we may have been instantiated
+ // to bounds in an earlier phase, and we *do* want to do inference
+ // in that case.
+
+ // Get back to the uninstantiated generic constructor.
+ // TODO(jmesserly): should we store this earlier in resolution?
+ // Or look it up, instead of jumping backwards through the Member?
+ var rawElement = originalElement.baseElement;
+
+ FunctionType constructorType =
+ StaticTypeAnalyzer.constructorToGenericFunctionType(rawElement);
+
+ inferred = _inferArgumentTypesForGeneric(
+ node, constructorType, constructor.type.typeArguments,
+ errorNode: node.constructorName);
+
+ if (inferred != null) {
+ ArgumentList arguments = node.argumentList;
+ InferenceContext.setType(arguments, inferred);
+ // Fix up the parameter elements based on inferred method.
+ arguments.correspondingStaticParameters =
+ resolveArgumentsToParameters(arguments, inferred.parameters, null);
+
+ constructor.type.type = inferred.returnType;
+ if (UnknownInferredType.isKnown(inferred)) {
+ inferenceContext.recordInference(node, inferred.returnType);
+ }
+
+ // Update the static element as well. This is used in some cases, such
+ // as computing constant values. It is stored in two places.
+ constructor.staticElement =
+ ConstructorMember.from(rawElement, inferred.returnType);
+ node.staticElement = constructor.staticElement;
}
+ }
+
+ if (inferred == null) {
+ InferenceContext.setType(node.argumentList, originalElement?.type);
+ }
+ }
- InferenceContext.setType(node.argumentList, contextType);
+ void _inferArgumentTypesForInvocation(InvocationExpression node) {
+ if (!strongMode) {
+ // Use propagated type inference for lambdas if not in strong mode.
+ _inferFunctionExpressionsParametersTypes(node.argumentList);
+ return;
}
+ DartType inferred = _inferArgumentTypesForGeneric(
+ node, node.function.staticType, node.typeArguments);
+ InferenceContext.setType(
+ node.argumentList, inferred ?? node.staticInvokeType);
}
void _inferFormalParameterList(FormalParameterList node, DartType type) {
@@ -7363,7 +7235,8 @@ abstract class ScopedVisitor extends UnifyingAstVisitor<Object> {
try {
if (classElement == null) {
AnalysisEngine.instance.logger.logInformation(
- "Missing element for class declaration ${node.name.name} in ${definingLibrary.source.fullName}",
+ "Missing element for class declaration ${node.name
+ .name} in ${definingLibrary.source.fullName}",
new CaughtException(new AnalysisException(), null));
super.visitClassDeclaration(node);
} else {
@@ -7491,7 +7364,8 @@ abstract class ScopedVisitor extends UnifyingAstVisitor<Object> {
try {
if (classElement == null) {
AnalysisEngine.instance.logger.logInformation(
- "Missing element for enum declaration ${node.name.name} in ${definingLibrary.source.fullName}",
+ "Missing element for enum declaration ${node.name
+ .name} in ${definingLibrary.source.fullName}",
new CaughtException(new AnalysisException(), null));
super.visitEnumDeclaration(node);
} else {
@@ -7607,7 +7481,8 @@ abstract class ScopedVisitor extends UnifyingAstVisitor<Object> {
try {
if (functionElement == null) {
AnalysisEngine.instance.logger.logInformation(
- "Missing element for top-level function ${node.name.name} in ${definingLibrary.source.fullName}",
+ "Missing element for top-level function ${node.name
+ .name} in ${definingLibrary.source.fullName}",
new CaughtException(new AnalysisException(), null));
} else {
nameScope = new FunctionScope(nameScope, functionElement);
@@ -7683,7 +7558,8 @@ abstract class ScopedVisitor extends UnifyingAstVisitor<Object> {
ParameterElement parameterElement = node.element;
if (parameterElement == null) {
AnalysisEngine.instance.logger.logInformation(
- "Missing element for function typed formal parameter ${node.identifier.name} in ${definingLibrary.source.fullName}",
+ "Missing element for function typed formal parameter ${node
+ .identifier.name} in ${definingLibrary.source.fullName}",
new CaughtException(new AnalysisException(), null));
} else {
nameScope = new EnclosedScope(nameScope);
@@ -7727,7 +7603,8 @@ abstract class ScopedVisitor extends UnifyingAstVisitor<Object> {
ExecutableElement methodElement = node.element;
if (methodElement == null) {
AnalysisEngine.instance.logger.logInformation(
- "Missing element for method ${node.name.name} in ${definingLibrary.source.fullName}",
+ "Missing element for method ${node.name.name} in ${definingLibrary
+ .source.fullName}",
new CaughtException(new AnalysisException(), null));
} else {
nameScope = new FunctionScope(nameScope, methodElement);
« no previous file with comments | « pkg/analyzer/lib/src/error/codes.dart ('k') | pkg/analyzer/lib/src/generated/static_type_analyzer.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698