[cfe] Add type checks on tearing off instance members

Closes #46784.

Bug: https://github.com/dart-lang/sdk/issues/46784
Change-Id: I7637618be0686bbffe6eb18a19049ec5da6059aa
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/208881
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Dmitry Stefantsov <dmitryas@google.com>
This commit is contained in:
Dmitry Stefantsov 2021-08-06 15:19:35 +00:00 committed by commit-bot@chromium.org
parent c66ae0027b
commit f77f8e5871
13 changed files with 115 additions and 11 deletions

View file

@ -4790,7 +4790,8 @@ class InferenceVisitor
checkReturn =
TypeInferrerImpl.returnedTypeParametersOccurNonCovariantly(
interfaceMember.enclosingClass!,
interfaceMember.function.returnType);
interfaceMember.function
.computeFunctionType(inferrer.library.nonNullable));
} else if (interfaceMember is Field) {
checkReturn =
TypeInferrerImpl.returnedTypeParametersOccurNonCovariantly(

View file

@ -65,7 +65,7 @@ static method test() → dynamic {
core::List<core::String*>* list1 = <core::String*>["a", "b", "c"].{core::Iterable::map}<core::String*>(a.{self::A::call}{(core::String*) →* core::String*}){((core::String*) →* core::String*) →* core::Iterable<core::String*>*}.{core::Iterable::toList}(){({growable: core::bool*}) →* core::List<core::String*>*};
core::List<core::String*>* list2 = <core::String*>["a", "b", "c"].{core::Iterable::map}<core::String*>(let final self::A* #t1 = a in #t1 == null ?{(core::String*) →* core::String*} null : #t1.{self::A::call}{(core::String*) →* core::String*}){((core::String*) →* core::String*) →* core::Iterable<core::String*>*}.{core::Iterable::toList}(){({growable: core::bool*}) →* core::List<core::String*>*};
self::B<core::String*>* b = new self::B::•<core::String*>();
core::List<core::String*>* list3 = <core::String*>["a", "b", "c"].{core::Iterable::map}<core::String*>(b.{self::B::call}{(core::String*) →* core::String*}){((core::String*) →* core::String*) →* core::Iterable<core::String*>*}.{core::Iterable::toList}(){({growable: core::bool*}) →* core::List<core::String*>*};
core::List<core::String*>* list3 = <core::String*>["a", "b", "c"].{core::Iterable::map}<core::String*>(b.{self::B::call}{(core::String*) →* core::String*} as{TypeError,CovarianceCheck} (core::String*) →* core::String*){((core::String*) →* core::String*) →* core::Iterable<core::String*>*}.{core::Iterable::toList}(){({growable: core::bool*}) →* core::List<core::String*>*};
core::List<core::String*>* list4 = <core::String*>["a", "b", "c"].{core::Iterable::map}<core::String*>(let final self::B<core::String*>* #t2 = b in #t2 == null ?{(core::String*) →* core::String*} null : #t2.{self::B::call}{(core::String*) →* core::String*}){((core::String*) →* core::String*) →* core::Iterable<core::String*>*}.{core::Iterable::toList}(){({growable: core::bool*}) →* core::List<core::String*>*};
self::C* c = new self::C::•();
core::List<core::String*>* list5 = <core::String*>["a", "b", "c"].{core::Iterable::map}<core::String*>(c.{self::C::call}{<T extends core::Object* = dynamic>(T*) →* T*}<core::String*>){((core::String*) →* core::String*) →* core::Iterable<core::String*>*}.{core::Iterable::toList}(){({growable: core::bool*}) →* core::List<core::String*>*};

View file

@ -65,7 +65,7 @@ static method test() → dynamic {
core::List<core::String*>* list1 = core::_GrowableList::_literal3<core::String*>("a", "b", "c").{core::Iterable::map}<core::String*>(a.{self::A::call}{(core::String*) →* core::String*}){((core::String*) →* core::String*) →* core::Iterable<core::String*>*}.{core::Iterable::toList}(){({growable: core::bool*}) →* core::List<core::String*>*};
core::List<core::String*>* list2 = core::_GrowableList::_literal3<core::String*>("a", "b", "c").{core::Iterable::map}<core::String*>(let final self::A* #t1 = a in #t1 == null ?{(core::String*) →* core::String*} null : #t1.{self::A::call}{(core::String*) →* core::String*}){((core::String*) →* core::String*) →* core::Iterable<core::String*>*}.{core::Iterable::toList}(){({growable: core::bool*}) →* core::List<core::String*>*};
self::B<core::String*>* b = new self::B::•<core::String*>();
core::List<core::String*>* list3 = core::_GrowableList::_literal3<core::String*>("a", "b", "c").{core::Iterable::map}<core::String*>(b.{self::B::call}{(core::String*) →* core::String*}){((core::String*) →* core::String*) →* core::Iterable<core::String*>*}.{core::Iterable::toList}(){({growable: core::bool*}) →* core::List<core::String*>*};
core::List<core::String*>* list3 = core::_GrowableList::_literal3<core::String*>("a", "b", "c").{core::Iterable::map}<core::String*>(b.{self::B::call}{(core::String*) →* core::String*} as{TypeError,CovarianceCheck} (core::String*) →* core::String*){((core::String*) →* core::String*) →* core::Iterable<core::String*>*}.{core::Iterable::toList}(){({growable: core::bool*}) →* core::List<core::String*>*};
core::List<core::String*>* list4 = core::_GrowableList::_literal3<core::String*>("a", "b", "c").{core::Iterable::map}<core::String*>(let final self::B<core::String*>* #t2 = b in #t2 == null ?{(core::String*) →* core::String*} null : #t2.{self::B::call}{(core::String*) →* core::String*}){((core::String*) →* core::String*) →* core::Iterable<core::String*>*}.{core::Iterable::toList}(){({growable: core::bool*}) →* core::List<core::String*>*};
self::C* c = new self::C::•();
core::List<core::String*>* list5 = core::_GrowableList::_literal3<core::String*>("a", "b", "c").{core::Iterable::map}<core::String*>(c.{self::C::call}{<T extends core::Object* = dynamic>(T*) →* T*}<core::String*>){((core::String*) →* core::String*) →* core::Iterable<core::String*>*}.{core::Iterable::toList}(){({growable: core::bool*}) →* core::List<core::String*>*};

View file

@ -0,0 +1,23 @@
// 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.
class A<X extends num> {
void f<Y extends X>(Y y) {}
}
expectThrows(void Function() f) {
try {
f();
} catch (e) {
return;
}
throw "Expected an exception to be thrown!";
}
main() {
A<num> a = new A<int>();
expectThrows(() {
void Function<Y extends num>(Y) f = a.f;
});
}

View file

@ -0,0 +1,6 @@
class A<X extends num> {
void f<Y extends X>(Y y) {}
}
expectThrows(void Function() f) {}
main() {}

View file

@ -0,0 +1,6 @@
class A<X extends num> {
void f<Y extends X>(Y y) {}
}
expectThrows(void Function() f) {}
main() {}

View file

@ -0,0 +1,25 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
class A<X extends core::num> extends core::Object {
synthetic constructor •() → self::A<self::A::X>
: super core::Object::•()
;
method f<generic-covariant-impl Y extends self::A::X>(self::A::f::Y y) → void {}
}
static method expectThrows(() → void f) → dynamic {
try {
f(){() → void};
}
on core::Object catch(final core::Object e) {
return;
}
throw "Expected an exception to be thrown!";
}
static method main() → dynamic {
self::A<core::num> a = new self::A::•<core::int>();
self::expectThrows(() → void {
<Y extends core::num>(Y) → void f = a.{self::A::f}{<generic-covariant-impl Y extends core::num>(Y) → void} as{TypeError,CovarianceCheck,ForNonNullableByDefault} <generic-covariant-impl Y extends core::num>(Y) → void;
});
}

View file

@ -0,0 +1,14 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
class A<X extends core::num> extends core::Object {
synthetic constructor •() → self::A<self::A::X>
;
method f<generic-covariant-impl Y extends self::A::X>(self::A::f::Y y) → void
;
}
static method expectThrows(() → void f) → dynamic
;
static method main() → dynamic
;

View file

@ -0,0 +1,25 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
class A<X extends core::num> extends core::Object {
synthetic constructor •() → self::A<self::A::X>
: super core::Object::•()
;
method f<generic-covariant-impl Y extends self::A::X>(self::A::f::Y y) → void {}
}
static method expectThrows(() → void f) → dynamic {
try {
f(){() → void};
}
on core::Object catch(final core::Object e) {
return;
}
throw "Expected an exception to be thrown!";
}
static method main() → dynamic {
self::A<core::num> a = new self::A::•<core::int>();
self::expectThrows(() → void {
<Y extends core::num>(Y) → void f = a.{self::A::f}{<generic-covariant-impl Y extends core::num>(Y) → void} as{TypeError,CovarianceCheck,ForNonNullableByDefault} <generic-covariant-impl Y extends core::num>(Y) → void;
});
}

View file

@ -15,7 +15,7 @@ class C<T> {
}
F<num> g1(C<num> c) {
return c.f1;
return c. /*@ checkReturn=(num*) ->* void*/ f1;
}
void g2(C<int> c, Object x) {
@ -24,7 +24,7 @@ void g2(C<int> c, Object x) {
}
G<List<num>, num> g3(C<num> c) {
return c.f2;
return c. /*@ checkReturn=(List<num*>*) ->* num**/ f2;
}
void test() {

View file

@ -23,14 +23,14 @@ class C<T extends core::Object* = dynamic> extends core::Object {
abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
}
static method g1(self::C<core::num*>* c) → (core::num*) →* void {
return c.{self::C::f1}{(core::num*) →* void};
return c.{self::C::f1}{(core::num*) →* void} as{TypeError,CovarianceCheck} (core::num*) →* void;
}
static method g2(self::C<core::int*>* c, core::Object* x) → void {
(core::Object*) →* void f = self::g1(c) as (core::Object*) →* void;
f(x){(core::Object*) →* void};
}
static method g3(self::C<core::num*>* c) → (core::List<core::num*>*) →* core::num* {
return c.{self::C::f2}{(core::List<core::num*>*) →* core::num*};
return c.{self::C::f2}{(core::List<core::num*>*) →* core::num*} as{TypeError,CovarianceCheck} (core::List<core::num*>*) →* core::num*;
}
static method test() → void {
(core::num*) →* void x = self::g1(new self::C::•<core::int*>());

View file

@ -23,14 +23,14 @@ class C<T extends core::Object* = dynamic> extends core::Object {
abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
}
static method g1(self::C<core::num*>* c) → (core::num*) →* void {
return c.{self::C::f1}{(core::num*) →* void};
return c.{self::C::f1}{(core::num*) →* void} as{TypeError,CovarianceCheck} (core::num*) →* void;
}
static method g2(self::C<core::int*>* c, core::Object* x) → void {
(core::Object*) →* void f = self::g1(c) as (core::Object*) →* void;
f(x){(core::Object*) →* void};
}
static method g3(self::C<core::num*>* c) → (core::List<core::num*>*) →* core::num* {
return c.{self::C::f2}{(core::List<core::num*>*) →* core::num*};
return c.{self::C::f2}{(core::List<core::num*>*) →* core::num*} as{TypeError,CovarianceCheck} (core::List<core::num*>*) →* core::num*;
}
static method test() → void {
(core::num*) →* void x = self::g1(new self::C::•<core::int*>());

View file

@ -109,7 +109,9 @@ bool containsFreeTypeVariables(DartType type) {
/// mapping to be used for replacing other types to use the new type parameters.
FreshTypeParameters getFreshTypeParameters(List<TypeParameter> typeParameters) {
List<TypeParameter> freshParameters = new List<TypeParameter>.generate(
typeParameters.length, (i) => new TypeParameter(typeParameters[i].name),
typeParameters.length,
(i) => new TypeParameter(typeParameters[i].name)
..flags = typeParameters[i].flags,
growable: true);
List<DartType> freshTypeArguments =
new List<DartType>.generate(typeParameters.length, (int i) {
@ -138,8 +140,10 @@ FreshTypeParameters getFreshTypeParameters(List<TypeParameter> typeParameters) {
class FreshTypeParameters {
/// The newly created type parameters.
final List<TypeParameter> freshTypeParameters;
/// List of [TypeParameterType]s for [TypeParameter].
final List<DartType> freshTypeArguments;
/// Substitution from the original type parameters to [freshTypeArguments].
final Substitution substitution;
@ -389,7 +393,7 @@ class _InnerTypeSubstitutor extends _TypeSubstitutor {
}
TypeParameter freshTypeParameter(TypeParameter node) {
TypeParameter fresh = new TypeParameter(node.name);
TypeParameter fresh = new TypeParameter(node.name)..flags = node.flags;
TypeParameterType typeParameterType = substitution[node] =
new TypeParameterType.forAlphaRenaming(node, fresh);
fresh.bound = visit(node.bound);