Skip to content

Commit 7ac2294

Browse files
jensjohacommit-bot@chromium.org
authored andcommitted
[CFE] More error for type variable in static contexts
Bug: 40918 Change-Id: Ibd7efa6618ea732a42bfb0042d5e9ef9bc8c0d8f Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/138803 Commit-Queue: Jens Johansen <[email protected]> Reviewed-by: Johnni Winther <[email protected]>
1 parent 30a12a3 commit 7ac2294

11 files changed

+767
-23
lines changed

pkg/front_end/lib/src/fasta/builder/function_builder.dart

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import 'dart:core' hide MapEntry;
99
import 'package:front_end/src/fasta/kernel/kernel_api.dart';
1010
import 'package:kernel/ast.dart';
1111

12-
import 'package:kernel/type_algebra.dart';
12+
import 'package:kernel/type_algebra.dart' show containsTypeVariable, substitute;
1313

1414
import '../../base/nnbd_mode.dart';
1515

@@ -429,13 +429,17 @@ abstract class FunctionBuilderImpl extends MemberBuilderImpl
429429
if (returnType != null) {
430430
result.returnType = returnType.build(library);
431431
}
432-
if (!isConstructor &&
433-
!isDeclarationInstanceMember &&
434-
parent is ClassBuilder) {
435-
ClassBuilder enclosingClassBuilder = parent;
436-
List<TypeParameter> typeParameters =
437-
enclosingClassBuilder.cls.typeParameters;
438-
if (typeParameters.isNotEmpty) {
432+
if (!isConstructor && !isDeclarationInstanceMember) {
433+
List<TypeParameter> typeParameters;
434+
if (parent is ClassBuilder) {
435+
ClassBuilder enclosingClassBuilder = parent;
436+
typeParameters = enclosingClassBuilder.cls.typeParameters;
437+
} else if (parent is ExtensionBuilder) {
438+
ExtensionBuilder enclosingExtensionBuilder = parent;
439+
typeParameters = enclosingExtensionBuilder.extension.typeParameters;
440+
}
441+
442+
if (typeParameters != null && typeParameters.isNotEmpty) {
439443
Map<TypeParameter, DartType> substitution;
440444
DartType removeTypeVariables(DartType type) {
441445
if (substitution == null) {

pkg/front_end/lib/src/fasta/kernel/body_builder.dart

Lines changed: 100 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ library fasta.body_builder;
66

77
import 'dart:core' hide MapEntry;
88

9+
import 'package:kernel/type_algebra.dart' show containsTypeVariable, substitute;
10+
911
import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis.dart';
1012

1113
import 'package:_fe_analyzer_shared/src/messages/severity.dart' show Severity;
@@ -4456,6 +4458,53 @@ class BodyBuilder extends ScopeListener<JumpTarget>
44564458
enterFunction();
44574459
}
44584460

4461+
_checkTypeParameters(FunctionNode function) {
4462+
if (member == null) return;
4463+
if (!member.isStatic) return;
4464+
List<TypeParameter> typeParameters;
4465+
if (member.parent is ClassBuilder) {
4466+
ClassBuilder enclosingClassBuilder = member.parent;
4467+
typeParameters = enclosingClassBuilder.cls.typeParameters;
4468+
} else if (member.parent is ExtensionBuilder) {
4469+
ExtensionBuilder enclosingExtensionBuilder = member.parent;
4470+
typeParameters = enclosingExtensionBuilder.extension.typeParameters;
4471+
}
4472+
if (typeParameters != null && typeParameters.isNotEmpty) {
4473+
Map<TypeParameter, DartType> substitution;
4474+
DartType removeTypeVariables(DartType type, int offset) {
4475+
if (substitution == null) {
4476+
substitution = <TypeParameter, DartType>{};
4477+
for (TypeParameter parameter in typeParameters) {
4478+
substitution[parameter] = const DynamicType();
4479+
}
4480+
}
4481+
libraryBuilder.addProblem(fasta.messageNonInstanceTypeVariableUse,
4482+
offset, noLength, member.fileUri);
4483+
return substitute(type, substitution);
4484+
}
4485+
4486+
Set<TypeParameter> set = typeParameters.toSet();
4487+
for (VariableDeclaration parameter in function.positionalParameters) {
4488+
parameter.fileOffset;
4489+
if (containsTypeVariable(parameter.type, set)) {
4490+
parameter.type =
4491+
removeTypeVariables(parameter.type, parameter.fileOffset);
4492+
}
4493+
}
4494+
for (VariableDeclaration parameter in function.namedParameters) {
4495+
if (containsTypeVariable(parameter.type, set)) {
4496+
parameter.type =
4497+
removeTypeVariables(parameter.type, parameter.fileOffset);
4498+
}
4499+
}
4500+
if (containsTypeVariable(function.returnType, set)) {
4501+
// TODO(CFE Team): The offset here doesn't actually point to the type.
4502+
function.returnType =
4503+
removeTypeVariables(function.returnType, function.fileOffset);
4504+
}
4505+
}
4506+
}
4507+
44594508
void pushNamedFunction(Token token, bool isFunctionExpression) {
44604509
Statement body = popStatement();
44614510
AsyncMarker asyncModifier = pop();
@@ -4472,6 +4521,7 @@ class BodyBuilder extends ScopeListener<JumpTarget>
44724521
}
44734522
FunctionNode function = formals.buildFunctionNode(libraryBuilder,
44744523
returnType, typeParameters, asyncModifier, body, token.charOffset);
4524+
_checkTypeParameters(function);
44754525

44764526
if (declaration is FunctionDeclaration) {
44774527
VariableDeclaration variable = declaration.variable;
@@ -4559,6 +4609,7 @@ class BodyBuilder extends ScopeListener<JumpTarget>
45594609
FunctionNode function = formals.buildFunctionNode(libraryBuilder, null,
45604610
typeParameters, asyncModifier, body, token.charOffset)
45614611
..fileOffset = beginToken.charOffset;
4612+
_checkTypeParameters(function);
45624613

45634614
Expression result;
45644615
if (constantContext != ConstantContext.none) {
@@ -5677,32 +5728,66 @@ class BodyBuilder extends ScopeListener<JumpTarget>
56775728
if (builder is NamedTypeBuilder && builder.declaration.isTypeVariable) {
56785729
TypeVariableBuilder typeParameterBuilder = builder.declaration;
56795730
TypeParameter typeParameter = typeParameterBuilder.parameter;
5680-
LocatedMessage message;
5681-
if (!isDeclarationInstanceContext && typeParameter.parent is Class) {
5682-
message = fasta.messageTypeVariableInStaticContext.withLocation(
5683-
unresolved.fileUri,
5684-
unresolved.charOffset,
5685-
typeParameter.name.length);
5686-
} else if (constantContext == ConstantContext.inferred) {
5687-
message = fasta.messageTypeVariableInConstantContext.withLocation(
5688-
unresolved.fileUri,
5689-
unresolved.charOffset,
5690-
typeParameter.name.length);
5691-
} else {
5692-
return unresolved;
5693-
}
5694-
addProblem(message.messageObject, message.charOffset, message.length);
5731+
LocatedMessage message = _validateTypeUseIsInternal(
5732+
builder, unresolved.fileUri, unresolved.charOffset);
5733+
if (message == null) return unresolved;
56955734
return new UnresolvedType(
56965735
new NamedTypeBuilder(
56975736
typeParameter.name, builder.nullabilityBuilder, null)
56985737
..bind(
56995738
new InvalidTypeDeclarationBuilder(typeParameter.name, message)),
57005739
unresolved.charOffset,
57015740
unresolved.fileUri);
5741+
} else if (builder is FunctionTypeBuilder) {
5742+
LocatedMessage message = _validateTypeUseIsInternal(
5743+
builder, unresolved.fileUri, unresolved.charOffset);
5744+
if (message == null) return unresolved;
5745+
// TODO(CFE Team): This should probably be some kind of InvalidType
5746+
// instead of null.
5747+
return new UnresolvedType(
5748+
null, unresolved.charOffset, unresolved.fileUri);
57025749
}
57035750
return unresolved;
57045751
}
57055752

5753+
LocatedMessage _validateTypeUseIsInternal(
5754+
TypeBuilder builder, Uri fileUri, int charOffset) {
5755+
if (builder is NamedTypeBuilder && builder.declaration.isTypeVariable) {
5756+
TypeVariableBuilder typeParameterBuilder = builder.declaration;
5757+
TypeParameter typeParameter = typeParameterBuilder.parameter;
5758+
LocatedMessage message;
5759+
if (!isDeclarationInstanceContext &&
5760+
(typeParameter.parent is Class ||
5761+
typeParameter.parent is Extension)) {
5762+
message = fasta.messageTypeVariableInStaticContext
5763+
.withLocation(fileUri, charOffset, typeParameter.name.length);
5764+
} else if (constantContext == ConstantContext.inferred) {
5765+
message = fasta.messageTypeVariableInConstantContext
5766+
.withLocation(fileUri, charOffset, typeParameter.name.length);
5767+
} else {
5768+
return null;
5769+
}
5770+
addProblem(message.messageObject, message.charOffset, message.length);
5771+
return message;
5772+
} else if (builder is FunctionTypeBuilder) {
5773+
LocatedMessage result =
5774+
_validateTypeUseIsInternal(builder.returnType, fileUri, charOffset);
5775+
if (result != null) {
5776+
return result;
5777+
}
5778+
if (builder.formals != null) {
5779+
for (FormalParameterBuilder formalParameterBuilder in builder.formals) {
5780+
result = _validateTypeUseIsInternal(
5781+
formalParameterBuilder.type, fileUri, charOffset);
5782+
if (result != null) {
5783+
return result;
5784+
}
5785+
}
5786+
}
5787+
}
5788+
return null;
5789+
}
5790+
57065791
@override
57075792
Expression evaluateArgumentsBefore(
57085793
Arguments arguments, Expression expression) {
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
class Foo<U> {
6+
static U foo1() { return null; }
7+
static void foo2(U x) { return null; }
8+
static void foo3() {
9+
U foo4;
10+
void foo5(U y) => print(y);
11+
U foo6() => null;
12+
void Function (U y) foo7 = (U y) => y;
13+
}
14+
static U Function() foo8() { return null; }
15+
static void Function(U) foo9() { return null; }
16+
static void foo10(U Function()) { return null; }
17+
// old syntax: variable named "U" of a function called 'Function'.
18+
static void foo11(void Function(U)) { return null; }
19+
static void foo12(void Function(U) b) { return null; }
20+
// old syntax: variable named "b" of type "U" of a function called 'Function'.
21+
static void foo13(void Function(U b)) { return null; }
22+
}
23+
24+
main() {}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:6:12: Error: Can only use type variables in instance methods.
6+
// static U foo1() { return null; }
7+
// ^
8+
//
9+
// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:7:15: Error: Can only use type variables in instance methods.
10+
// static void foo2(U x) { return null; }
11+
// ^
12+
//
13+
// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:14:23: Error: Can only use type variables in instance methods.
14+
// static U Function() foo8() { return null; }
15+
// ^
16+
//
17+
// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:15:27: Error: Can only use type variables in instance methods.
18+
// static void Function(U) foo9() { return null; }
19+
// ^
20+
//
21+
// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:16:15: Error: Can only use type variables in instance methods.
22+
// static void foo10(U Function()) { return null; }
23+
// ^
24+
//
25+
// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:19:15: Error: Can only use type variables in instance methods.
26+
// static void foo12(void Function(U) b) { return null; }
27+
// ^
28+
//
29+
// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:21:15: Error: Can only use type variables in instance methods.
30+
// static void foo13(void Function(U b)) { return null; }
31+
// ^
32+
//
33+
import self as self;
34+
import "dart:core" as core;
35+
36+
class Foo<U extends core::Object* = dynamic> extends core::Object {
37+
synthetic constructor •() → self::Foo<self::Foo::U*>*
38+
;
39+
static method foo1() → dynamic
40+
;
41+
static method foo2(generic-covariant-impl dynamic x) → void
42+
;
43+
static method foo3() → void
44+
;
45+
static method foo8() → () →* dynamic
46+
;
47+
static method foo9() → (dynamic) →* void
48+
;
49+
static method foo10(generic-covariant-impl () →* dynamic Function) → void
50+
;
51+
static method foo11((dynamic) →* void Function) → void
52+
;
53+
static method foo12((dynamic) →* void b) → void
54+
;
55+
static method foo13((dynamic) →* void Function) → void
56+
;
57+
}
58+
static method main() → dynamic
59+
;
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:6:12: Error: Can only use type variables in instance methods.
6+
// static U foo1() { return null; }
7+
// ^
8+
//
9+
// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:7:15: Error: Can only use type variables in instance methods.
10+
// static void foo2(U x) { return null; }
11+
// ^
12+
//
13+
// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:14:23: Error: Can only use type variables in instance methods.
14+
// static U Function() foo8() { return null; }
15+
// ^
16+
//
17+
// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:15:27: Error: Can only use type variables in instance methods.
18+
// static void Function(U) foo9() { return null; }
19+
// ^
20+
//
21+
// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:16:15: Error: Can only use type variables in instance methods.
22+
// static void foo10(U Function()) { return null; }
23+
// ^
24+
//
25+
// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:19:15: Error: Can only use type variables in instance methods.
26+
// static void foo12(void Function(U) b) { return null; }
27+
// ^
28+
//
29+
// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:21:15: Error: Can only use type variables in instance methods.
30+
// static void foo13(void Function(U b)) { return null; }
31+
// ^
32+
//
33+
// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:7:20: Error: Type variables can't be used in static members.
34+
// static void foo2(U x) { return null; }
35+
// ^
36+
//
37+
// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:9:5: Error: Type variables can't be used in static members.
38+
// U foo4;
39+
// ^
40+
//
41+
// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:10:17: Error: Can only use type variables in instance methods.
42+
// void foo5(U y) => print(y);
43+
// ^
44+
//
45+
// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:11:11: Error: Can only use type variables in instance methods.
46+
// U foo6() => null;
47+
// ^
48+
//
49+
// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:12:20: Error: Type variables can't be used in static members.
50+
// void Function (U y) foo7 = (U y) => y;
51+
// ^
52+
//
53+
// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:12:35: Error: Can only use type variables in instance methods.
54+
// void Function (U y) foo7 = (U y) => y;
55+
// ^
56+
//
57+
// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:12:19: Error: Type variables can't be used in static members.
58+
// void Function (U y) foo7 = (U y) => y;
59+
// ^
60+
//
61+
// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:16:31: Error: Type variables can't be used in static members.
62+
// static void foo10(U Function()) { return null; }
63+
// ^
64+
//
65+
// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:19:35: Error: Type variables can't be used in static members.
66+
// static void foo12(void Function(U) b) { return null; }
67+
// ^
68+
//
69+
// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:19:34: Error: Type variables can't be used in static members.
70+
// static void foo12(void Function(U) b) { return null; }
71+
// ^
72+
//
73+
// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:21:34: Error: Type variables can't be used in static members.
74+
// static void foo13(void Function(U b)) { return null; }
75+
// ^
76+
//
77+
import self as self;
78+
import "dart:core" as core;
79+
80+
class Foo<U extends core::Object* = dynamic> extends core::Object {
81+
synthetic constructor •() → self::Foo<self::Foo::U*>*
82+
: super core::Object::•()
83+
;
84+
static method foo1() → dynamic {
85+
return null;
86+
}
87+
static method foo2(generic-covariant-impl dynamic x) → void {
88+
return null;
89+
}
90+
static method foo3() → void {
91+
invalid-type foo4;
92+
function foo5(dynamic y) → void
93+
return core::print(y);
94+
function foo6() → dynamic
95+
return null;
96+
(dynamic) →* dynamic foo7 = (dynamic y) → dynamic => y;
97+
}
98+
static method foo8() → () →* dynamic {
99+
return null;
100+
}
101+
static method foo9() → (dynamic) →* void {
102+
return null;
103+
}
104+
static method foo10(generic-covariant-impl () →* dynamic Function) → void {
105+
return null;
106+
}
107+
static method foo11((dynamic) →* void Function) → void {
108+
return null;
109+
}
110+
static method foo12((dynamic) →* void b) → void {
111+
return null;
112+
}
113+
static method foo13((dynamic) →* void Function) → void {
114+
return null;
115+
}
116+
}
117+
static method main() → dynamic {}

0 commit comments

Comments
 (0)