[cfe] Setup correct scope for builder outline expressions on extension fields

Closes https://github.com/dart-lang/sdk/issues/47345

Change-Id: I3a666fde4d6dd802e6101ccbd55dff11c0179fba
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/215401
Reviewed-by: Jens Johansen <jensj@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
Johnni Winther 2021-10-04 12:14:57 +00:00 committed by commit-bot@chromium.org
parent fcd684e7d1
commit b6b81ebad1
19 changed files with 271 additions and 13 deletions

View file

@ -426,8 +426,14 @@ class SourceFieldBuilder extends MemberBuilderImpl implements FieldBuilder {
_fieldEncoding.completeSignature(coreTypes);
for (Annotatable annotatable in _fieldEncoding.annotatables) {
MetadataBuilder.buildAnnotations(annotatable, metadata, library,
classBuilder, this, fileUri, classBuilder?.scope ?? library.scope);
MetadataBuilder.buildAnnotations(
annotatable,
metadata,
library,
declarationBuilder,
this,
fileUri,
declarationBuilder?.scope ?? library.scope);
}
// For modular compilation we need to include initializers of all const
@ -439,10 +445,10 @@ class SourceFieldBuilder extends MemberBuilderImpl implements FieldBuilder {
isClassMember &&
classBuilder!.declaresConstConstructor)) &&
_constInitializerToken != null) {
Scope scope = classBuilder?.scope ?? library.scope;
Scope scope = declarationBuilder?.scope ?? library.scope;
BodyBuilder bodyBuilder = library.loader
.createBodyBuilderForOutlineExpression(
library, classBuilder, this, scope, fileUri);
library, declarationBuilder, this, scope, fileUri);
bodyBuilder.constantContext =
isConst ? ConstantContext.inferred : ConstantContext.required;
Expression initializer = bodyBuilder.typeInferrer.inferFieldInitializer(

View file

@ -207,6 +207,11 @@ abstract class MemberBuilderImpl extends ModifierBuilderImpl
return buffer;
}
/// The builder for the enclosing class or extension, if any.
DeclarationBuilder? get declarationBuilder =>
parent is DeclarationBuilder ? parent as DeclarationBuilder : null;
/// The builder for the enclosing class, if any.
ClassBuilder? get classBuilder =>
parent is ClassBuilder ? parent as ClassBuilder : null;
}

View file

@ -1,7 +1,9 @@
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// @dart=2.9
class Class {
@pragma('dart2js:noInline')
instanceMethod() {}

View file

@ -43,9 +43,9 @@ static method main() → dynamic
Extra constant evaluation status:
Evaluated: ConstructorInvocation @ org-dartlang-testcase:///annotations.dart:6:4 -> InstanceConstant(const pragma{pragma.name: "dart2js:noInline", pragma.options: null})
Evaluated: ConstructorInvocation @ org-dartlang-testcase:///annotations.dart:9:4 -> InstanceConstant(const pragma{pragma.name: "dart2js:noInline", pragma.options: null})
Evaluated: ConstructorInvocation @ org-dartlang-testcase:///annotations.dart:14:4 -> InstanceConstant(const pragma{pragma.name: "dart2js:noInline", pragma.options: null})
Evaluated: ConstructorInvocation @ org-dartlang-testcase:///annotations.dart:17:4 -> InstanceConstant(const pragma{pragma.name: "dart2js:noInline", pragma.options: null})
Evaluated: ConstructorInvocation @ org-dartlang-testcase:///annotations.dart:21:2 -> InstanceConstant(const pragma{pragma.name: "dart2js:noInline", pragma.options: null})
Evaluated: ConstructorInvocation @ org-dartlang-testcase:///annotations.dart:8:4 -> InstanceConstant(const pragma{pragma.name: "dart2js:noInline", pragma.options: null})
Evaluated: ConstructorInvocation @ org-dartlang-testcase:///annotations.dart:11:4 -> InstanceConstant(const pragma{pragma.name: "dart2js:noInline", pragma.options: null})
Evaluated: ConstructorInvocation @ org-dartlang-testcase:///annotations.dart:16:4 -> InstanceConstant(const pragma{pragma.name: "dart2js:noInline", pragma.options: null})
Evaluated: ConstructorInvocation @ org-dartlang-testcase:///annotations.dart:19:4 -> InstanceConstant(const pragma{pragma.name: "dart2js:noInline", pragma.options: null})
Evaluated: ConstructorInvocation @ org-dartlang-testcase:///annotations.dart:23:2 -> InstanceConstant(const pragma{pragma.name: "dart2js:noInline", pragma.options: null})
Extra constant evaluation: evaluated: 8, effectively constant: 5

View file

@ -0,0 +1,25 @@
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// Test that extension member annotations can access other extension static
// members from the same extension by simple name.
extension E on int {
@constField
static const int constField = 1;
@constField2
static const int constField1 = 2;
@constField1
static const int constField2 = 3;
@constField
static void staticMethod() {}
@constField
void instanceMethod() {}
}
main() {}

View file

@ -0,0 +1,14 @@
extension E on int {
@constField
static const int constField = 1;
@constField2
static const int constField1 = 2;
@constField1
static const int constField2 = 3;
@constField
static void staticMethod() {}
@constField
void instanceMethod() {}
}
main() {}

View file

@ -0,0 +1,14 @@
extension E on int {
@constField
static const int constField = 1;
@constField2
static const int constField1 = 2;
@constField1
static const int constField2 = 3;
@constField
static void staticMethod() {}
@constField
void instanceMethod() {}
}
main() {}

View file

@ -0,0 +1,31 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
extension E on core::int {
static field constField = self::E|constField;
static field constField1 = self::E|constField1;
static field constField2 = self::E|constField2;
static method staticMethod = self::E|staticMethod;
method instanceMethod = self::E|instanceMethod;
tearoff instanceMethod = self::E|get#instanceMethod;
}
@#C1
static const field core::int E|constField = #C1;
@#C2
static const field core::int E|constField1 = #C3;
@#C3
static const field core::int E|constField2 = #C2;
@#C1
static method E|staticMethod() → void {}
@#C1
static method E|instanceMethod(lowered final core::int #this) → void {}
static method E|get#instanceMethod(lowered final core::int #this) → () → void
return () → void => self::E|instanceMethod(#this);
static method main() → dynamic {}
constants {
#C1 = 1
#C2 = 3
#C3 = 2
}

View file

@ -0,0 +1,37 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
extension E on core::int {
static field constField = self::E|constField;
static field constField1 = self::E|constField1;
static field constField2 = self::E|constField2;
static method staticMethod = self::E|staticMethod;
method instanceMethod = self::E|instanceMethod;
tearoff instanceMethod = self::E|get#instanceMethod;
}
@self::E|constField
static const field core::int E|constField = 1;
@self::E|constField2
static const field core::int E|constField1 = 2;
@self::E|constField1
static const field core::int E|constField2 = 3;
@self::E|constField
static method E|staticMethod() → void
;
@self::E|constField
static method E|instanceMethod(lowered final core::int #this) → void
;
static method E|get#instanceMethod(lowered final core::int #this) → () → void
return () → void => self::E|instanceMethod(#this);
static method main() → dynamic
;
Extra constant evaluation status:
Evaluated: StaticGet @ org-dartlang-testcase:///annotations_scope.dart:18:4 -> IntConstant(1)
Evaluated: StaticGet @ org-dartlang-testcase:///annotations_scope.dart:21:4 -> IntConstant(1)
Evaluated: StaticGet @ org-dartlang-testcase:///annotations_scope.dart:9:4 -> IntConstant(1)
Evaluated: StaticGet @ org-dartlang-testcase:///annotations_scope.dart:12:4 -> IntConstant(3)
Evaluated: StaticGet @ org-dartlang-testcase:///annotations_scope.dart:15:4 -> IntConstant(2)
Extra constant evaluation: evaluated: 8, effectively constant: 5

View file

@ -0,0 +1,31 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
extension E on core::int {
static field constField = self::E|constField;
static field constField1 = self::E|constField1;
static field constField2 = self::E|constField2;
static method staticMethod = self::E|staticMethod;
method instanceMethod = self::E|instanceMethod;
tearoff instanceMethod = self::E|get#instanceMethod;
}
@#C1
static const field core::int E|constField = #C1;
@#C2
static const field core::int E|constField1 = #C3;
@#C3
static const field core::int E|constField2 = #C2;
@#C1
static method E|staticMethod() → void {}
@#C1
static method E|instanceMethod(lowered final core::int #this) → void {}
static method E|get#instanceMethod(lowered final core::int #this) → () → void
return () → void => self::E|instanceMethod(#this);
static method main() → dynamic {}
constants {
#C1 = 1
#C2 = 3
#C3 = 2
}

View file

@ -0,0 +1,12 @@
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
void main() {}
class Foo {}
extension on Foo {
static const bar = 1;
static const doubleBar = bar * 2;
}

View file

@ -0,0 +1,8 @@
void main() {}
class Foo {}
extension on Foo {
static const bar = 1;
static const doubleBar = bar * 2;
}

View file

@ -0,0 +1,8 @@
class Foo {}
extension on Foo {
static const bar = 1;
static const doubleBar = bar * 2;
}
void main() {}

View file

@ -0,0 +1,21 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
class Foo extends core::Object {
synthetic constructor •() → self::Foo
: super core::Object::•()
;
}
extension _extension#0 on self::Foo {
static field bar = self::_extension#0|bar;
static field doubleBar = self::_extension#0|doubleBar;
}
static const field core::int _extension#0|bar = #C1;
static const field core::int _extension#0|doubleBar = #C2;
static method main() → void {}
constants {
#C1 = 1
#C2 = 2
}

View file

@ -0,0 +1,21 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
class Foo extends core::Object {
synthetic constructor •() → self::Foo
;
}
extension _extension#0 on self::Foo {
static field bar = self::_extension#0|bar;
static field doubleBar = self::_extension#0|doubleBar;
}
static const field core::int _extension#0|bar = 1;
static const field core::int _extension#0|doubleBar = self::_extension#0|bar.{core::num::*}(2){(core::num) → core::int};
static method main() → void
;
Extra constant evaluation status:
Evaluated: InstanceInvocation @ org-dartlang-testcase:///issue47345.dart:11:32 -> IntConstant(2)
Extra constant evaluation: evaluated: 1, effectively constant: 1

View file

@ -0,0 +1,21 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
class Foo extends core::Object {
synthetic constructor •() → self::Foo
: super core::Object::•()
;
}
extension _extension#0 on self::Foo {
static field bar = self::_extension#0|bar;
static field doubleBar = self::_extension#0|doubleBar;
}
static const field core::int _extension#0|bar = #C1;
static const field core::int _extension#0|doubleBar = #C2;
static method main() → void {}
constants {
#C1 = 1
#C2 = 2
}

View file

@ -1,7 +1,9 @@
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// @dart=2.9
extension Test<T> on T {
T Function(T) get test => (a) => this;
}

View file

@ -2,7 +2,7 @@ library;
//
// Problems in library:
//
// pkg/front_end/testcases/extensions/language_issue1182.dart:11:25: Error: A value of type 'num Function(num)' can't be assigned to a variable of type 'S Function(S)'.
// pkg/front_end/testcases/extensions/language_issue1182.dart:13:25: Error: A value of type 'num Function(num)' can't be assigned to a variable of type 'S Function(S)'.
// S Function(S) f = x.test;
// ^
//
@ -14,7 +14,7 @@ class Foo<S extends core::num*> extends core::Object {
: super core::Object::•()
;
method test1(covariant-by-class self::Foo::S* x) → void {
(self::Foo::S*) →* self::Foo::S* f = invalid-expression "pkg/front_end/testcases/extensions/language_issue1182.dart:11:25: Error: A value of type 'num Function(num)' can't be assigned to a variable of type 'S Function(S)'.
(self::Foo::S*) →* self::Foo::S* f = invalid-expression "pkg/front_end/testcases/extensions/language_issue1182.dart:13:25: Error: A value of type 'num Function(num)' can't be assigned to a variable of type 'S Function(S)'.
S Function(S) f = x.test;
^" in self::Test|get#test<core::num*>(x) as{TypeError} Never;
}

View file

@ -2,7 +2,7 @@ library;
//
// Problems in library:
//
// pkg/front_end/testcases/extensions/language_issue1182.dart:11:25: Error: A value of type 'num Function(num)' can't be assigned to a variable of type 'S Function(S)'.
// pkg/front_end/testcases/extensions/language_issue1182.dart:13:25: Error: A value of type 'num Function(num)' can't be assigned to a variable of type 'S Function(S)'.
// S Function(S) f = x.test;
// ^
//
@ -14,7 +14,7 @@ class Foo<S extends core::num*> extends core::Object {
: super core::Object::•()
;
method test1(covariant-by-class self::Foo::S* x) → void {
(self::Foo::S*) →* self::Foo::S* f = invalid-expression "pkg/front_end/testcases/extensions/language_issue1182.dart:11:25: Error: A value of type 'num Function(num)' can't be assigned to a variable of type 'S Function(S)'.
(self::Foo::S*) →* self::Foo::S* f = invalid-expression "pkg/front_end/testcases/extensions/language_issue1182.dart:13:25: Error: A value of type 'num Function(num)' can't be assigned to a variable of type 'S Function(S)'.
S Function(S) f = x.test;
^" in self::Test|get#test<core::num*>(x) as{TypeError} Never;
}