Support patched generic methods.

R=sigmund@google.com

Review URL: https://codereview.chromium.org/2535213003 .
This commit is contained in:
Johnni Winther 2016-11-30 09:20:42 +01:00
parent 3af747810f
commit 44bdc75827
6 changed files with 100 additions and 8 deletions

View file

@ -385,6 +385,7 @@ enum MessageKind {
PATCH_POINT_TO_SETTER,
PATCH_REQUIRED_PARAMETER_COUNT_MISMATCH,
PATCH_RETURN_TYPE_MISMATCH,
PATCH_TYPE_VARIABLES_MISMATCH,
PLEASE_REPORT_THE_CRASH,
POSITIONAL_PARAMETER_WITH_EQUALS,
POTENTIAL_MUTATION,
@ -1239,12 +1240,14 @@ main() => f<int>(42);
]),
MessageKind.TYPE_VARIABLE_FROM_METHOD_CONSIDERED_DYNAMIC:
const MessageTemplate(
MessageKind.TYPE_VARIABLE_FROM_METHOD_CONSIDERED_DYNAMIC,
"Method type variables are treated as `dynamic` in `as` expressions.",
howToFix: "Try using the upper bound of the type variable, or check "
"that the blind success of the test does not introduce bugs.",
examples: const [
const MessageTemplate(
MessageKind.TYPE_VARIABLE_FROM_METHOD_CONSIDERED_DYNAMIC,
"Method type variables are treated as `dynamic` in `as` "
"expressions.",
howToFix:
"Try using the upper bound of the type variable, or check "
"that the blind success of the test does not introduce bugs.",
examples: const [
"""
// Method type variables are not reified, so they cannot be tested dynamically.
bool f<T>(Object o) => o as T;
@ -3530,6 +3533,11 @@ part of test.main;
// Patch errors start.
//////////////////////////////////////////////////////////////////////////////
MessageKind.PATCH_TYPE_VARIABLES_MISMATCH: const MessageTemplate(
MessageKind.PATCH_TYPE_VARIABLES_MISMATCH,
"Patch type variables do not match "
"type variables on origin method '#{methodName}'."),
MessageKind.PATCH_RETURN_TYPE_MISMATCH: const MessageTemplate(
MessageKind.PATCH_RETURN_TYPE_MISMATCH,
"Patch return type '#{patchReturnType}' does not match "

View file

@ -1417,6 +1417,14 @@ abstract class ConstructorBodyElement extends MethodElement {
/// [GenericElement] defines the common interface for generic functions and
/// [TypeDeclarationElement].
abstract class GenericElement extends Element implements AstElement {
/// Do not use [computeType] outside of the resolver.
///
/// Trying to access a type that has not been computed in resolution is an
/// error and calling [computeType] covers that error.
/// This method will go away!
@deprecated
DartType computeType(Resolution resolution);
/**
* The type variables declared on this declaration. The type variables are not
* available until the type of the element has been computed through

View file

@ -106,10 +106,24 @@ class PatchResolverTask extends CompilerTask {
void checkMatchingPatchSignatures(
FunctionElement origin, FunctionElement patch) {
// TODO(johnniwinther): Show both origin and patch locations on errors.
FunctionExpression originTree = origin.node;
FunctionSignature originSignature = origin.functionSignature;
FunctionExpression patchTree = patch.node;
FunctionSignature patchSignature = patch.functionSignature;
if ('${originTree.typeVariables}' != '${patchTree.typeVariables}') {
reporter.withCurrentElement(patch, () {
Node errorNode = patchTree.typeVariables != null
? patchTree.typeVariables
: patchTree;
reporter.reportError(
reporter.createMessage(
errorNode,
MessageKind.PATCH_TYPE_VARIABLES_MISMATCH,
{'methodName': origin.name}),
[reporter.createMessage(origin, MessageKind.THIS_IS_THE_METHOD)]);
});
}
if (originSignature.type.returnType != patchSignature.type.returnType) {
reporter.withCurrentElement(patch, () {
Node errorNode =

View file

@ -149,7 +149,8 @@ class PatchParserTask extends CompilerTask {
DiagnosticReporter get reporter => compiler.reporter;
PatchParserTask(Compiler compiler)
: compiler = compiler, super(compiler.measurer);
: compiler = compiler,
super(compiler.measurer);
/**
* Scans a library patch file, applies the method patches and
@ -248,7 +249,7 @@ class PatchMemberListener extends MemberListener {
* declarations.
*/
class PatchClassElementParser extends PartialParser {
PatchClassElementParser(Listener listener): super(listener);
PatchClassElementParser(Listener listener) : super(listener);
Token parseClassBody(Token token) => fullParseClassBody(token);
}

View file

@ -307,6 +307,11 @@ class SignatureResolver extends MappingVisitor<FormalElementX> {
DiagnosticReporter reporter = resolution.reporter;
List<DartType> createTypeVariables(NodeList typeVariableNodes) {
if (element.isPatch) {
FunctionTypedElement origin = element.origin;
origin.computeType(resolution);
return origin.typeVariables;
}
if (typeVariableNodes == null) return const <DartType>[];
// Create the types and elements corresponding to [typeVariableNodes].

View file

@ -166,6 +166,59 @@ Future testPatchFunctionMetadata() async {
"Unexpected patch metadata: ${patch.metadata}.");
}
Future testPatchFunctionGeneric() async {
var compiler = await applyPatch(
"external T test<T>();", "@patch T test<T>() { return null; } ");
Element origin = ensure(
compiler, "test", compiler.commonElements.coreLibrary.find,
expectIsPatched: true, checkHasBody: true);
ensure(compiler, "test", compiler.commonElements.coreLibrary.patch.find,
expectIsPatch: true, checkHasBody: true);
compiler.resolver.resolve(origin);
DiagnosticCollector collector = compiler.diagnosticCollector;
Expect.isTrue(
collector.warnings.isEmpty, "Unexpected warnings: ${collector.warnings}");
Expect.isTrue(
collector.errors.isEmpty, "Unexpected errors: ${collector.errors}");
}
Future testPatchFunctionGenericExtraTypeVariable() async {
var compiler = await applyPatch(
"external T test<T>();", "@patch T test<T, S>() { return null; } ");
Element origin = ensure(
compiler, "test", compiler.commonElements.coreLibrary.find,
expectIsPatched: true, checkHasBody: true);
ensure(compiler, "test", compiler.commonElements.coreLibrary.patch.find,
expectIsPatch: true, checkHasBody: true);
compiler.resolver.resolve(origin);
DiagnosticCollector collector = compiler.diagnosticCollector;
Expect.isTrue(
collector.warnings.isEmpty, "Unexpected warnings: ${collector.warnings}");
Expect.equals(1, collector.errors.length);
Expect.isTrue(collector.errors.first.message.kind ==
MessageKind.PATCH_TYPE_VARIABLES_MISMATCH);
}
Future testPatchFunctionGenericDifferentNames() async {
var compiler = await applyPatch(
"external T test<T, S>();", "@patch T test<S, T>() { return null; } ");
Element origin = ensure(
compiler, "test", compiler.commonElements.coreLibrary.find,
expectIsPatched: true, checkHasBody: true);
ensure(compiler, "test", compiler.commonElements.coreLibrary.patch.find,
expectIsPatch: true, checkHasBody: true);
compiler.resolver.resolve(origin);
DiagnosticCollector collector = compiler.diagnosticCollector;
Expect.isTrue(
collector.warnings.isEmpty, "Unexpected warnings: ${collector.warnings}");
Expect.equals(1, collector.errors.length);
Expect.isTrue(collector.errors.first.message.kind ==
MessageKind.PATCH_TYPE_VARIABLES_MISMATCH);
}
Future testPatchVersioned() async {
String fullPatch = "test(){return 'string';}";
String lazyPatch = "test(){return 'new and improved string';}";
@ -1086,6 +1139,9 @@ main() {
await testPatchRedirectingConstructor();
await testPatchFunction();
await testPatchFunctionMetadata();
await testPatchFunctionGeneric();
await testPatchFunctionGenericExtraTypeVariable();
await testPatchFunctionGenericDifferentNames();
await testPatchMember();
await testPatchGetter();
await testRegularMember();