Skip to content

Commit

Permalink
[cfe] Class type parameters wildcards are non-binding.
Browse files Browse the repository at this point in the history
Wildcard type parameters are not added to the scope of the class. They do not collide with other wildcards or other wildcard type parameters.

Bug: #55655
Change-Id: I473a5023c570623fe2a11df5c07d491082bab642
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/371943
Commit-Queue: Kallen Tu <[email protected]>
Reviewed-by: Johnni Winther <[email protected]>
Reviewed-by: Chloe Stefantsova <[email protected]>
  • Loading branch information
kallentu authored and Commit Queue committed Jun 20, 2024
1 parent 818f977 commit bf31d0e
Show file tree
Hide file tree
Showing 11 changed files with 279 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,8 @@ class NominalVariableBuilder extends TypeVariableBuilderBase {

final TypeParameter actualParameter;

final bool isWildcard;

@override
NominalVariableBuilder? actualOrigin;

Expand All @@ -196,7 +198,8 @@ class NominalVariableBuilder extends TypeVariableBuilderBase {
{TypeBuilder? bound,
required TypeVariableKind kind,
Variance? variableVariance,
List<MetadataBuilder>? metadata})
List<MetadataBuilder>? metadata,
this.isWildcard = false})
: actualParameter =
new TypeParameter(name == noNameSentinel ? null : name, null)
..fileOffset = charOffset
Expand All @@ -220,7 +223,7 @@ class NominalVariableBuilder extends TypeVariableBuilderBase {
///
/// class A<X extends A<X>> {}
NominalVariableBuilder.fromKernel(TypeParameter parameter,
{required Loader? loader})
{required Loader? loader, this.isWildcard = false})
: actualParameter = parameter,
// TODO(johnniwinther): Do we need to support synthesized type
// parameters from kernel?
Expand Down
1 change: 1 addition & 0 deletions pkg/front_end/lib/src/fasta/scope.dart
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,7 @@ class Scope extends MutableScope {
Scope newScope = new Scope.nested(this, "type variables",
isModifiable: false, kind: ScopeKind.typeParameters);
for (NominalVariableBuilder t in typeVariables) {
if (t.isWildcard) continue;
(newScope._local ??= {})[t.name] = t;
}
return newScope;
Expand Down
11 changes: 9 additions & 2 deletions pkg/front_end/lib/src/fasta/source/source_library_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2583,7 +2583,10 @@ class SourceCompilationUnitImpl implements SourceCompilationUnit {
{required TypeVariableKind kind}) {
NominalVariableBuilder builder = new NominalVariableBuilder(
name, _sourceLibraryBuilder, charOffset, fileUri,
bound: bound, metadata: metadata, kind: kind);
bound: bound,
metadata: metadata,
kind: kind,
isWildcard: libraryFeatures.wildcardVariables.isEnabled && name == '_');

unboundNominalVariables.add(builder);
return builder;
Expand Down Expand Up @@ -2611,6 +2614,7 @@ class SourceCompilationUnitImpl implements SourceCompilationUnit {
<String, NominalVariableBuilder>{};
for (NominalVariableBuilder tv in typeVariables) {
NominalVariableBuilder? existing = typeVariablesByName[tv.name];
if (tv.isWildcard) continue;
if (existing != null) {
if (existing.kind == TypeVariableKind.extensionSynthesized) {
// The type parameter from the extension is shadowed by the type
Expand Down Expand Up @@ -2673,7 +2677,9 @@ class SourceCompilationUnitImpl implements SourceCompilationUnit {
?.clone(newTypes, _sourceLibraryBuilder, declaration),
kind: kind,
variableVariance:
variable.parameter.isLegacyCovariant ? null : variable.variance);
variable.parameter.isLegacyCovariant ? null : variable.variance,
isWildcard: libraryFeatures.wildcardVariables.isEnabled &&
variable.isWildcard);
copy.add(newVariable);
unboundNominalVariables.add(newVariable);
}
Expand Down Expand Up @@ -6219,6 +6225,7 @@ class TypeParameterScopeBuilder {
if (typeVariables != null) {
map = <String, NominalVariableBuilder>{};
for (NominalVariableBuilder builder in typeVariables) {
if (builder.isWildcard) continue;
map[builder.name] = builder;
}
}
Expand Down
1 change: 1 addition & 0 deletions pkg/front_end/testcases/strong.status
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@ value_class/copy_with_call_sites: RuntimeError # Expected
value_class/simple: RuntimeError # Expected
value_class/value_extends_non_value: RuntimeError # Expected
value_class/value_implements_non_value: RuntimeError # Expected
wildcard_variables/class_type_parameters: semiFuzzFailureOnForceRebuildBodies # Expected
wildcard_variables/local_var_no_shadowing: semiFuzzFailureOnForceRebuildBodies # Expected
wildcard_variables/top_level_function_no_shadow: semiFuzzFailureOnForceRebuildBodies # Expected

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (c) 2024, 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.

typedef _ = BB;

class AA {}

class BB extends AA {}

class A<T, U extends AA> {}

class B<_, _ extends AA> extends A<_, _> {
int foo<_ extends _>([int _ = 2]) => 1;
}

class C<T, _ extends _> extends A<T, _> {
static const int _ = 1;
}

class D<_, _> {}

class DoesNotUseTypeVariable<_> {
Type returnsBB() {
return _;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
library;
import self as self;
import "dart:core" as core;

typedef _ = self::BB;
class AA extends core::Object {
synthetic constructor •() → self::AA
: super core::Object::•()
;
}
class BB extends self::AA {
synthetic constructor •() → self::BB
: super self::AA::•()
;
}
class A<T extends core::Object? = dynamic, U extends self::AA> extends core::Object {
synthetic constructor •() → self::A<self::A::T%, self::A::U>
: super core::Object::•()
;
}
class B<_ extends core::Object? = dynamic, _ extends self::AA> extends self::A<self::BB, self::BB> {
synthetic constructor •() → self::B<self::B::_%, self::B::_>
: super self::A::•()
;
method foo<_ extends self::BB>([wildcard core::int _ = #C1]) → core::int
return 1;
}
class C<T extends core::Object? = dynamic, _ extends self::BB> extends self::A<self::C::T%, self::BB> {
static const field core::int _ = #C2;
synthetic constructor •() → self::C<self::C::T%, self::C::_>
: super self::A::•()
;
}
class D<_ extends core::Object? = dynamic, _ extends core::Object? = dynamic> extends core::Object {
synthetic constructor •() → self::D<self::D::_%, self::D::_%>
: super core::Object::•()
;
}
class DoesNotUseTypeVariable<_ extends core::Object? = dynamic> extends core::Object {
synthetic constructor •() → self::DoesNotUseTypeVariable<self::DoesNotUseTypeVariable::_%>
: super core::Object::•()
;
method returnsBB() → core::Type {
return #C3;
}
}

constants {
#C1 = 2
#C2 = 1
#C3 = TypeLiteralConstant(self::BB)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
library;
import self as self;
import "dart:core" as core;

typedef _ = self::BB;
class AA extends core::Object {
synthetic constructor •() → self::AA
: super core::Object::•()
;
}
class BB extends self::AA {
synthetic constructor •() → self::BB
: super self::AA::•()
;
}
class A<T extends core::Object? = dynamic, U extends self::AA> extends core::Object {
synthetic constructor •() → self::A<self::A::T%, self::A::U>
: super core::Object::•()
;
}
class B<_ extends core::Object? = dynamic, _ extends self::AA> extends self::A<self::BB, self::BB> {
synthetic constructor •() → self::B<self::B::_%, self::B::_>
: super self::A::•()
;
method foo<_ extends self::BB>([wildcard core::int _ = #C1]) → core::int
return 1;
}
class C<T extends core::Object? = dynamic, _ extends self::BB> extends self::A<self::C::T%, self::BB> {
static const field core::int _ = #C2;
synthetic constructor •() → self::C<self::C::T%, self::C::_>
: super self::A::•()
;
}
class D<_ extends core::Object? = dynamic, _ extends core::Object? = dynamic> extends core::Object {
synthetic constructor •() → self::D<self::D::_%, self::D::_%>
: super core::Object::•()
;
}
class DoesNotUseTypeVariable<_ extends core::Object? = dynamic> extends core::Object {
synthetic constructor •() → self::DoesNotUseTypeVariable<self::DoesNotUseTypeVariable::_%>
: super core::Object::•()
;
method returnsBB() → core::Type {
return #C3;
}
}

constants {
#C1 = 2
#C2 = 1
#C3 = TypeLiteralConstant(self::BB)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
library;
import self as self;
import "dart:core" as core;

typedef _ = self::BB;
class AA extends core::Object {
synthetic constructor •() → self::AA
;
}
class BB extends self::AA {
synthetic constructor •() → self::BB
;
}
class A<T extends core::Object? = dynamic, U extends self::AA> extends core::Object {
synthetic constructor •() → self::A<self::A::T%, self::A::U>
;
}
class B<_ extends core::Object? = dynamic, _ extends self::AA> extends self::A<self::BB, self::BB> {
synthetic constructor •() → self::B<self::B::_%, self::B::_>
;
method foo<_ extends self::BB>([wildcard core::int _ = 2]) → core::int
;
}
class C<T extends core::Object? = dynamic, _ extends self::BB> extends self::A<self::C::T%, self::BB> {
static const field core::int _ = 1;
synthetic constructor •() → self::C<self::C::T%, self::C::_>
;
}
class D<_ extends core::Object? = dynamic, _ extends core::Object? = dynamic> extends core::Object {
synthetic constructor •() → self::D<self::D::_%, self::D::_%>
;
}
class DoesNotUseTypeVariable<_ extends core::Object? = dynamic> extends core::Object {
synthetic constructor •() → self::DoesNotUseTypeVariable<self::DoesNotUseTypeVariable::_%>
;
method returnsBB() → core::Type
;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
library;
import self as self;
import "dart:core" as core;

typedef _ = self::BB;
class AA extends core::Object {
synthetic constructor •() → self::AA
: super core::Object::•()
;
}
class BB extends self::AA {
synthetic constructor •() → self::BB
: super self::AA::•()
;
}
class A<T extends core::Object? = dynamic, U extends self::AA> extends core::Object {
synthetic constructor •() → self::A<self::A::T%, self::A::U>
: super core::Object::•()
;
}
class B<_ extends core::Object? = dynamic, _ extends self::AA> extends self::A<self::BB, self::BB> {
synthetic constructor •() → self::B<self::B::_%, self::B::_>
: super self::A::•()
;
method foo<_ extends self::BB>([wildcard core::int _ = #C1]) → core::int
return 1;
}
class C<T extends core::Object? = dynamic, _ extends self::BB> extends self::A<self::C::T%, self::BB> {
static const field core::int _ = #C2;
synthetic constructor •() → self::C<self::C::T%, self::C::_>
: super self::A::•()
;
}
class D<_ extends core::Object? = dynamic, _ extends core::Object? = dynamic> extends core::Object {
synthetic constructor •() → self::D<self::D::_%, self::D::_%>
: super core::Object::•()
;
}
class DoesNotUseTypeVariable<_ extends core::Object? = dynamic> extends core::Object {
synthetic constructor •() → self::DoesNotUseTypeVariable<self::DoesNotUseTypeVariable::_%>
: super core::Object::•()
;
method returnsBB() → core::Type {
return #C3;
}
}

constants {
#C1 = 2
#C2 = 1
#C3 = TypeLiteralConstant(self::BB)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
typedef _ = BB;

class AA {}

class BB extends AA {}

class A<T, U extends AA> {}

class B<_, _ extends AA> extends A<_, _> {
int foo<_ extends _>([int _ = 2]) => 1;
}

class C<T, _ extends _> extends A<T, _> {
static const int _ = 1;
}

class D<_, _> {}

class DoesNotUseTypeVariable<_> {
Type returnsBB() {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
class A<T, U extends AA> {}

class AA {}

class B<_, _ extends AA> extends A<_, _> {
int foo<_ extends _>([int _ = 2]) => 1;
}

class BB extends AA {}

class C<T, _ extends _> extends A<T, _> {
static const int _ = 1;
}

class D<_, _> {}

class DoesNotUseTypeVariable<_> {
Type returnsBB() {}
}

typedef _ = BB;

0 comments on commit bf31d0e

Please sign in to comment.