Pass InheritanceManager2 into resolver, use for BinaryExpression.

Ideally I think we should not use Expression.staticParameterElement to
get back to the corresponding parameter of the invoked FunctionType,
and do this check directly during resolution.

R=brianwilkerson@google.com

Change-Id: I6dbb5bf63f7eaad7f19b31129319e32dd4455acc
Reviewed-on: https://dart-review.googlesource.com/c/77641
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
Konstantin Shcheglov
2018-10-02 21:48:36 +00:00
committed by commit-bot@chromium.org
parent 3ef994c287
commit 80db08809c
11 changed files with 146 additions and 78 deletions
+11
View File
@@ -874,6 +874,17 @@ abstract class BinaryExpression extends Expression
* [expression].
*/
void set rightOperand(Expression expression);
/**
* The function type of the invocation, or `null` if the AST structure has
* not been resolved, or if the invocation could not be resolved.
*/
FunctionType get staticInvokeType;
/**
* Sets the function type of the invocation.
*/
void set staticInvokeType(FunctionType value);
}
/**
@@ -590,15 +590,15 @@ class LibraryAnalyzer {
_libraryElement, source, _typeProvider, errorListener,
nameScope: libraryScope));
unit.accept(new PartialResolverVisitor(_libraryElement, source,
_typeProvider, AnalysisErrorListener.NULL_LISTENER));
unit.accept(new PartialResolverVisitor(_inheritance, _libraryElement,
source, _typeProvider, AnalysisErrorListener.NULL_LISTENER));
// Nothing for RESOLVED_UNIT8?
// Nothing for RESOLVED_UNIT9?
// Nothing for RESOLVED_UNIT10?
unit.accept(new ResolverVisitor(
_libraryElement, source, _typeProvider, errorListener));
_inheritance, _libraryElement, source, _typeProvider, errorListener));
}
/**
+8 -18
View File
@@ -1045,6 +1045,9 @@ class BinaryExpressionImpl extends ExpressionImpl implements BinaryExpression {
@override
MethodElement staticElement;
@override
FunctionType staticInvokeType;
/**
* Initialize a newly created binary expression.
*/
@@ -1095,23 +1098,6 @@ class BinaryExpressionImpl extends ExpressionImpl implements BinaryExpression {
_rightOperand = _becomeParentOf(expression as ExpressionImpl);
}
/**
* If the AST structure has been resolved, and the function being invoked is
* known based on static type information, then return the parameter element
* representing the parameter to which the value of the right operand will be
* bound. Otherwise, return `null`.
*/
ParameterElement get _staticParameterElementForRightOperand {
if (staticElement == null) {
return null;
}
List<ParameterElement> parameters = staticElement.parameters;
if (parameters.length < 1) {
return null;
}
return parameters[0];
}
@override
E accept<E>(AstVisitor<E> visitor) => visitor.visitBinaryExpression(this);
@@ -4163,7 +4149,11 @@ abstract class ExpressionImpl extends AstNodeImpl implements Expression {
}
} else if (parent is BinaryExpressionImpl) {
if (identical(parent.rightOperand, this)) {
return parent._staticParameterElementForRightOperand;
var parameters = parent.staticInvokeType?.parameters;
if (parameters != null && parameters.isNotEmpty) {
return parameters[0];
}
return null;
}
} else if (parent is AssignmentExpressionImpl) {
if (identical(parent.rightHandSide, this)) {
@@ -11,12 +11,14 @@ import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/error/error.dart';
import 'package:analyzer/src/dart/ast/ast.dart'
show
BinaryExpressionImpl,
ChildEntities,
IdentifierImpl,
PrefixedIdentifierImpl,
SimpleIdentifierImpl;
import 'package:analyzer/src/dart/ast/token.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/inheritance_manager2.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/engine.dart';
@@ -82,6 +84,11 @@ import 'package:analyzer/src/task/strong/checker.dart';
* error).
*/
class ElementResolver extends SimpleAstVisitor<Object> {
/**
* The manager for the inheritance mappings.
*/
final InheritanceManager2 _inheritance;
/**
* The resolver driving this participant.
*/
@@ -90,7 +97,7 @@ class ElementResolver extends SimpleAstVisitor<Object> {
/**
* The element for the library containing the compilation unit being visited.
*/
LibraryElement _definingLibrary;
final LibraryElement _definingLibrary;
/**
* The type representing the type 'dynamic'.
@@ -114,8 +121,9 @@ class ElementResolver extends SimpleAstVisitor<Object> {
* Initialize a newly created visitor to work for the given [_resolver] to
* resolve the nodes in a compilation unit.
*/
ElementResolver(this._resolver, {this.reportConstEvaluationErrors: true}) {
this._definingLibrary = _resolver.definingLibrary;
ElementResolver(this._resolver, {this.reportConstEvaluationErrors: true})
: _inheritance = _resolver.inheritance,
_definingLibrary = _resolver.definingLibrary {
_dynamicType = _resolver.typeProvider.dynamicType;
_typeType = _resolver.typeProvider.typeType;
_promoteManager = _resolver.promoteManager;
@@ -1573,6 +1581,25 @@ class ElementResolver extends SimpleAstVisitor<Object> {
return null;
}
/**
* Look up the [FunctionType] of a getter or a method with the given [name]
* in the given [targetType]. The [target] is the target of the invocation,
* or `null` if there is no target.
*/
FunctionType _lookUpGetterType(
Expression target, DartType targetType, String name) {
targetType = _resolveTypeParameter(targetType);
if (targetType is InterfaceType) {
var nameObject = new Name(_definingLibrary.source.uri, name);
return _inheritance.getMember(
targetType,
nameObject,
forSuper: target is SuperExpression,
);
}
return null;
}
/**
* Look up the method with the given [methodName] in the given [type]. Return
* the element representing the method that was found, or `null` if there is
@@ -1867,23 +1894,24 @@ class ElementResolver extends SimpleAstVisitor<Object> {
void _resolveBinaryExpression(BinaryExpression node, String methodName) {
Expression leftOperand = node.leftOperand;
if (leftOperand != null) {
DartType staticType = _getStaticType(leftOperand);
MethodElement staticMethod =
_lookUpMethod(leftOperand, staticType, methodName);
node.staticElement = staticMethod;
if (_shouldReportMissingMember(staticType, staticMethod)) {
DartType leftType = _getStaticType(leftOperand);
var invokeType = _lookUpGetterType(leftOperand, leftType, methodName);
var invokeElement = invokeType?.element;
node.staticElement = invokeElement;
node.staticInvokeType = invokeType;
if (_shouldReportMissingMember(leftType, invokeElement)) {
if (leftOperand is SuperExpression) {
_recordUndefinedToken(
staticType.element,
leftType.element,
StaticTypeWarningCode.UNDEFINED_SUPER_OPERATOR,
node.operator,
[methodName, staticType.displayName]);
[methodName, leftType.displayName]);
} else {
_recordUndefinedToken(
staticType.element,
leftType.element,
StaticTypeWarningCode.UNDEFINED_OPERATOR,
node.operator,
[methodName, staticType.displayName]);
[methodName, leftType.displayName]);
}
}
}
+33 -14
View File
@@ -3816,10 +3816,14 @@ class InstanceFieldResolverVisitor extends ResolverVisitor {
/// resolution. The [nameScope] is the scope used to resolve identifiers in
/// the node that will first be visited. If `null` or unspecified, a new
/// [LibraryScope] will be created based on the [definingLibrary].
InstanceFieldResolverVisitor(LibraryElement definingLibrary, Source source,
TypeProvider typeProvider, AnalysisErrorListener errorListener,
InstanceFieldResolverVisitor(
InheritanceManager2 inheritance,
LibraryElement definingLibrary,
Source source,
TypeProvider typeProvider,
AnalysisErrorListener errorListener,
{Scope nameScope})
: super(definingLibrary, source, typeProvider, errorListener,
: super(inheritance, definingLibrary, source, typeProvider, errorListener,
nameScope: nameScope);
/// Resolve the instance fields in the given compilation unit [node].
@@ -3996,10 +4000,14 @@ class PartialResolverVisitor extends ResolverVisitor {
/// created based on [definingLibrary]. The [typeAnalyzerFactory] is used to
/// create the type analyzer. If `null` or unspecified, a type analyzer of
/// type [StaticTypeAnalyzer] will be created.
PartialResolverVisitor(LibraryElement definingLibrary, Source source,
TypeProvider typeProvider, AnalysisErrorListener errorListener,
PartialResolverVisitor(
InheritanceManager2 inheritance,
LibraryElement definingLibrary,
Source source,
TypeProvider typeProvider,
AnalysisErrorListener errorListener,
{Scope nameScope})
: super(definingLibrary, source, typeProvider, errorListener,
: super(inheritance, definingLibrary, source, typeProvider, errorListener,
nameScope: nameScope);
@override
@@ -4152,6 +4160,11 @@ class ResolverErrorCode extends ErrorCode {
/// Instances of the class `ResolverVisitor` are used to resolve the nodes
/// within a single compilation unit.
class ResolverVisitor extends ScopedVisitor {
/**
* The manager for the inheritance mappings.
*/
final InheritanceManager2 inheritance;
/// The object used to resolve the element associated with the current node.
ElementResolver elementResolver;
@@ -4217,8 +4230,12 @@ class ResolverVisitor extends ScopedVisitor {
/// created based on [definingLibrary]. The [typeAnalyzerFactory] is used to
/// create the type analyzer. If `null` or unspecified, a type analyzer of
/// type [StaticTypeAnalyzer] will be created.
ResolverVisitor(LibraryElement definingLibrary, Source source,
TypeProvider typeProvider, AnalysisErrorListener errorListener,
ResolverVisitor(
this.inheritance,
LibraryElement definingLibrary,
Source source,
TypeProvider typeProvider,
AnalysisErrorListener errorListener,
{Scope nameScope,
bool propagateTypes: true,
reportConstEvaluationErrors: true})
@@ -4606,12 +4623,14 @@ class ResolverVisitor extends ScopedVisitor {
contextType = leftType;
}
InferenceContext.setType(rightOperand, contextType);
} else if (node.staticElement != null &&
node.staticElement.parameters.isNotEmpty) {
// If this is a user-defined operator, set the right operand context
// using the operator method's parameter type.
var rightParam = node.staticElement.parameters[0];
InferenceContext.setType(rightOperand, rightParam.type);
} else {
var invokeType = node.staticInvokeType;
if (invokeType != null && invokeType.parameters.isNotEmpty) {
// If this is a user-defined operator, set the right operand context
// using the operator method's parameter type.
var rightParam = invokeType.parameters[0];
InferenceContext.setType(rightOperand, rightParam.type);
}
}
rightOperand?.accept(this);
}
@@ -368,8 +368,7 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
_analyzeLeastUpperBound(node, node.leftOperand, node.rightOperand);
return null;
}
ExecutableElement staticMethodElement = node.staticElement;
DartType staticType = _computeStaticReturnType(staticMethodElement);
DartType staticType = node.staticInvokeType?.returnType ?? _dynamicType;
staticType = _typeSystem.refineBinaryExpressionType(
node.leftOperand.staticType,
node.operator.type,
+13 -2
View File
@@ -64,6 +64,7 @@ import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/dart/constant/value.dart';
import 'package:analyzer/src/dart/element/builder.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/inheritance_manager2.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/resolver/inheritance_manager.dart';
import 'package:analyzer/src/generated/engine.dart';
@@ -454,6 +455,9 @@ abstract class ClassElementForLink extends Object
@override
LibraryElementForLink get library => enclosingElement.library;
@override
Source get librarySource => library.source;
@override
List<MethodElementForLink> get methods;
@@ -2106,6 +2110,9 @@ abstract class ExecutableElementForLink extends Object
return _inferredReturnType;
}
@override
bool get isAbstract => serializedExecutable.isAbstract;
@override
bool get isGenerator => serializedExecutable.isGenerator;
@@ -2241,8 +2248,9 @@ class ExprTypeComputer {
nameScope = new ClassScope(
new TypeParameterScope(nameScope, enclosingClass), enclosingClass);
}
var inheritance = new InheritanceManager2(linker.typeSystem);
var resolverVisitor = new ResolverVisitor(
library, source, typeProvider, errorListener,
inheritance, library, source, typeProvider, errorListener,
nameScope: nameScope,
propagateTypes: false,
reportConstEvaluationErrors: false);
@@ -2253,7 +2261,7 @@ class ExprTypeComputer {
library, source, typeProvider, errorListener,
nameScope: nameScope);
var partialResolverVisitor = new PartialResolverVisitor(
library, source, typeProvider, errorListener,
inheritance, library, source, typeProvider, errorListener,
nameScope: nameScope);
return new ExprTypeComputer._(
unit._unitResynthesizer,
@@ -4295,6 +4303,9 @@ class PropertyAccessorElementForLink_Variable extends Object
@override
Element get enclosingElement => variable.enclosingElement;
@override
bool get isAbstract => false;
@override
bool get isGetter => !isSetter;
+14 -5
View File
@@ -3402,6 +3402,7 @@ class InferStaticVariableTypeTask extends InferStaticVariableTask {
CompilationUnit unit = getRequiredInput(UNIT_INPUT);
TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT);
var inheritance = new InheritanceManager2(context.typeSystem);
// If we're not in a dependency cycle, and we have no type annotation,
// re-resolve the right hand side and do inference.
@@ -3417,7 +3418,7 @@ class InferStaticVariableTypeTask extends InferStaticVariableTask {
ResolutionContext resolutionContext =
ResolutionContextBuilder.contextFor(initializer);
ResolverVisitor visitor = new ResolverVisitor(
ResolverVisitor visitor = new ResolverVisitor(inheritance,
variable.library, variable.source, typeProvider, errorListener,
nameScope: resolutionContext.scope);
if (resolutionContext.enclosingClassDeclaration != null) {
@@ -4021,11 +4022,16 @@ class PartiallyResolveUnitReferencesTask extends SourceBasedAnalysisTask {
CompilationUnit unit = getRequiredInput(UNIT_INPUT);
CompilationUnitElement unitElement = unit.declaredElement;
TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT);
var inheritance = new InheritanceManager2(context.typeSystem);
//
// Resolve references and record outputs.
//
PartialResolverVisitor visitor = new PartialResolverVisitor(libraryElement,
unitElement.source, typeProvider, AnalysisErrorListener.NULL_LISTENER);
PartialResolverVisitor visitor = new PartialResolverVisitor(
inheritance,
libraryElement,
unitElement.source,
typeProvider,
AnalysisErrorListener.NULL_LISTENER);
unit.accept(visitor);
//
// Record outputs.
@@ -4553,12 +4559,14 @@ class ResolveInstanceFieldsInUnitTask extends SourceBasedAnalysisTask {
LibraryElement libraryElement = getRequiredInput(LIBRARY_INPUT);
CompilationUnit unit = getRequiredInput(UNIT_INPUT);
TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT);
var inheritance = new InheritanceManager2(context.typeSystem);
CompilationUnitElement unitElement = unit.declaredElement;
//
// Resolve references.
//
InstanceFieldResolverVisitor visitor = new InstanceFieldResolverVisitor(
inheritance,
libraryElement,
unitElement.source,
typeProvider,
@@ -4995,13 +5003,14 @@ class ResolveUnitTask extends SourceBasedAnalysisTask {
LibraryElement libraryElement = getRequiredInput(LIBRARY_INPUT);
CompilationUnit unit = getRequiredInput(UNIT_INPUT);
TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT);
var inheritance = new InheritanceManager2(context.typeSystem);
//
// Resolve everything.
//
CompilationUnitElement unitElement = unit.declaredElement;
RecordingErrorListener errorListener = new RecordingErrorListener();
ResolverVisitor visitor = new ResolverVisitor(
libraryElement, unitElement.source, typeProvider, errorListener);
ResolverVisitor visitor = new ResolverVisitor(inheritance, libraryElement,
unitElement.source, typeProvider, errorListener);
unit.accept(visitor);
//
// Compute constant expressions' dependencies.
+6 -12
View File
@@ -227,24 +227,18 @@ class CodeChecker extends RecursiveAstVisitor {
void visitBinaryExpression(BinaryExpression node) {
var op = node.operator;
if (op.isUserDefinableOperator) {
var element = node.staticElement;
if (element == null) {
var invokeType = node.staticInvokeType;
if (invokeType == null) {
// Dynamic invocation
// TODO(vsm): Move this logic to the resolver?
if (op.type != TokenType.EQ_EQ && op.type != TokenType.BANG_EQ) {
_recordDynamicInvoke(node, node.leftOperand);
}
} else {
// Method invocation.
if (element is MethodElement) {
var type = element.type;
// Analyzer should enforce number of parameter types, but check in
// case we have erroneous input.
if (type.normalParameterTypes.isNotEmpty) {
checkArgument(node.rightOperand, type.normalParameterTypes[0]);
}
} else {
// TODO(vsm): Assert that the analyzer found an error here?
// Analyzer should enforce number of parameter types, but check in
// case we have erroneous input.
if (invokeType.normalParameterTypes.isNotEmpty) {
checkArgument(node.rightOperand, invokeType.normalParameterTypes[0]);
}
}
} else {
@@ -11,13 +11,13 @@ import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/inheritance_manager2.dart';
import 'package:analyzer/src/generated/element_resolver.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/testing/ast_test_factory.dart';
import 'package:analyzer/src/generated/testing/element_factory.dart';
import 'package:analyzer/src/generated/testing/test_type_provider.dart';
import 'package:analyzer/src/source/source_resource.dart';
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:test/test.dart';
@@ -312,7 +312,7 @@ class ElementResolverTest extends EngineTestCase with ResourceProviderMixin {
/**
* The type provider used to access the types.
*/
TestTypeProvider _typeProvider;
TypeProvider _typeProvider;
/**
* The library containing the code being resolved.
@@ -382,8 +382,7 @@ class ElementResolverTest extends EngineTestCase with ResourceProviderMixin {
void setUp() {
super.setUp();
_listener = new GatheringErrorListener();
_typeProvider = new TestTypeProvider();
_resolver = _createResolver();
_createResolver();
}
test_lookUpMethodInInterfaces() async {
@@ -1136,18 +1135,21 @@ class ElementResolverTest extends EngineTestCase with ResourceProviderMixin {
/**
* Create and return the resolver used by the tests.
*/
ElementResolver _createResolver() {
void _createResolver() {
InternalAnalysisContext context = AnalysisContextFactory.contextWithCore(
resourceProvider: resourceProvider);
_typeProvider = context.typeProvider;
var inheritance = new InheritanceManager2(context.typeSystem);
Source source = new FileSource(getFile("/test.dart"));
CompilationUnitElementImpl unit = new CompilationUnitElementImpl();
unit.librarySource = unit.source = source;
_definingLibrary = ElementFactory.library(context, "test");
_definingLibrary.definingCompilationUnit = unit;
_visitor = new ResolverVisitor(
_definingLibrary, source, _typeProvider, _listener,
inheritance, _definingLibrary, source, _typeProvider, _listener,
nameScope: new LibraryScope(_definingLibrary));
return _visitor.elementResolver;
_resolver = _visitor.elementResolver;
}
/**
@@ -8,7 +8,9 @@ import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/ast/ast.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/inheritance_manager2.dart';
import 'package:analyzer/src/dart/element/member.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/generated/engine.dart';
@@ -557,9 +559,10 @@ class StaticTypeAnalyzerTest extends EngineTestCase with ResourceProviderMixin {
void test_visitBinaryExpression_slash() {
// 2 / 2
BinaryExpression node = AstTestFactory.binaryExpression(
BinaryExpressionImpl node = AstTestFactory.binaryExpression(
_resolvedInteger(2), TokenType.SLASH, _resolvedInteger(2));
node.staticElement = getMethod(_typeProvider.numType, "/");
node.staticInvokeType = node.staticElement.type;
expect(_analyze(node), same(_typeProvider.doubleType));
_listener.assertNoErrors();
}
@@ -574,12 +577,13 @@ class StaticTypeAnalyzerTest extends EngineTestCase with ResourceProviderMixin {
MethodElement operator =
ElementFactory.methodElement("*", typeA, [_typeProvider.doubleType]);
classA.methods = <MethodElement>[operator];
BinaryExpression node = AstTestFactory.binaryExpression(
BinaryExpressionImpl node = AstTestFactory.binaryExpression(
AstTestFactory.asExpression(
AstTestFactory.identifier3("a"), AstTestFactory.typeName(classA)),
TokenType.PLUS,
_resolvedDouble(2.0));
node.staticElement = operator;
node.staticInvokeType = node.staticElement.type;
expect(_analyze(node), same(typeA));
_listener.assertNoErrors();
}
@@ -1534,6 +1538,7 @@ class StaticTypeAnalyzerTest extends EngineTestCase with ResourceProviderMixin {
context = AnalysisContextFactory.contextWithCore(
resourceProvider: resourceProvider);
}
var inheritance = new InheritanceManager2(context.typeSystem);
Source source = new FileSource(getFile("/lib.dart"));
CompilationUnitElementImpl definingCompilationUnit =
new CompilationUnitElementImpl();
@@ -1544,7 +1549,7 @@ class StaticTypeAnalyzerTest extends EngineTestCase with ResourceProviderMixin {
definingLibrary.definingCompilationUnit = definingCompilationUnit;
_typeProvider = context.typeProvider;
_visitor = new ResolverVisitor(
definingLibrary, source, _typeProvider, _listener,
inheritance, definingLibrary, source, _typeProvider, _listener,
nameScope: new LibraryScope(definingLibrary));
_visitor.overrideManager.enterScope();
return _visitor.typeAnalyzer;