Skip to content

Commit

Permalink
[cfe] Handle unforseen type parameter intersections
Browse files Browse the repository at this point in the history
Closes #42089

Change-Id: Ifb0dc0073e004051ae40aed51db24b0d4b10f50d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/152646
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
  • Loading branch information
johnniwinther authored and commit-bot@chromium.org committed Jul 6, 2020
1 parent 878e2ca commit 5d1fbe0
Show file tree
Hide file tree
Showing 16 changed files with 493 additions and 11 deletions.
2 changes: 2 additions & 0 deletions pkg/front_end/test/spell_checking_list_code.txt
Expand Up @@ -53,6 +53,7 @@ arises
arising
arity
artifact
artifacts
artificial
asgerf
askesc
Expand Down Expand Up @@ -894,6 +895,7 @@ repeating
replacements
replacer
replaces
replicated
repo
repositories
requirement
Expand Down
12 changes: 12 additions & 0 deletions pkg/front_end/testcases/nnbd/issue42089.dart
@@ -0,0 +1,12 @@
// 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.

test<X>(X? x) {
if (x is String?) {
Object o = x;
o = x;
}
}

main() {}
8 changes: 8 additions & 0 deletions pkg/front_end/testcases/nnbd/issue42089.dart.outline.expect
@@ -0,0 +1,8 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;

static method test<X extends core::Object? = dynamic>(self::test::X? x) → dynamic
;
static method main() → dynamic
;
30 changes: 30 additions & 0 deletions pkg/front_end/testcases/nnbd/issue42089.dart.strong.expect
@@ -0,0 +1,30 @@
library /*isNonNullableByDefault*/;
//
// Problems in library:
//
// pkg/front_end/testcases/nnbd/issue42089.dart:7:16: Error: A value of type 'X?' can't be assigned to a variable of type 'Object'.
// - 'Object' is from 'dart:core'.
// Object o = x;
// ^
//
// pkg/front_end/testcases/nnbd/issue42089.dart:8:9: Error: A value of type 'X?' can't be assigned to a variable of type 'Object'.
// - 'Object' is from 'dart:core'.
// o = x;
// ^
//
import self as self;
import "dart:core" as core;

static method test<X extends core::Object? = dynamic>(self::test::X? x) → dynamic {
if(x is{ForNonNullableByDefault} core::String?) {
core::Object o = let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/nnbd/issue42089.dart:7:16: Error: A value of type 'X?' can't be assigned to a variable of type 'Object'.
- 'Object' is from 'dart:core'.
Object o = x;
^" in x{self::test::X? & core::String? /* '?' & '?' = '?' */} as{TypeError,ForNonNullableByDefault} core::Object;
o = let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/nnbd/issue42089.dart:8:9: Error: A value of type 'X?' can't be assigned to a variable of type 'Object'.
- 'Object' is from 'dart:core'.
o = x;
^" in x{self::test::X? & core::String? /* '?' & '?' = '?' */} as{TypeError,ForNonNullableByDefault} core::Object;
}
}
static method main() → dynamic {}
@@ -0,0 +1,30 @@
library /*isNonNullableByDefault*/;
//
// Problems in library:
//
// pkg/front_end/testcases/nnbd/issue42089.dart:7:16: Error: A value of type 'X?' can't be assigned to a variable of type 'Object'.
// - 'Object' is from 'dart:core'.
// Object o = x;
// ^
//
// pkg/front_end/testcases/nnbd/issue42089.dart:8:9: Error: A value of type 'X?' can't be assigned to a variable of type 'Object'.
// - 'Object' is from 'dart:core'.
// o = x;
// ^
//
import self as self;
import "dart:core" as core;

static method test<X extends core::Object? = dynamic>(self::test::X? x) → dynamic {
if(x is{ForNonNullableByDefault} core::String?) {
core::Object o = let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/nnbd/issue42089.dart:7:16: Error: A value of type 'X?' can't be assigned to a variable of type 'Object'.
- 'Object' is from 'dart:core'.
Object o = x;
^" in let self::test::X? & core::String? /* '?' & '?' = '?' */ #t2 = x{self::test::X? & core::String? /* '?' & '?' = '?' */} in #t2.==(null) ?{core::Object} #t2 as{TypeError,ForNonNullableByDefault} core::Object : #t2{core::Object};
o = let final<BottomType> #t3 = invalid-expression "pkg/front_end/testcases/nnbd/issue42089.dart:8:9: Error: A value of type 'X?' can't be assigned to a variable of type 'Object'.
- 'Object' is from 'dart:core'.
o = x;
^" in let self::test::X? & core::String? /* '?' & '?' = '?' */ #t4 = x{self::test::X? & core::String? /* '?' & '?' = '?' */} in #t4.==(null) ?{core::Object} #t4 as{TypeError,ForNonNullableByDefault} core::Object : #t4{core::Object};
}
}
static method main() → dynamic {}
@@ -0,0 +1,2 @@
test<X>(X? x) {}
main() {}
@@ -0,0 +1,2 @@
main() {}
test<X>(X? x) {}
30 changes: 30 additions & 0 deletions pkg/front_end/testcases/nnbd/issue42089.dart.weak.expect
@@ -0,0 +1,30 @@
library /*isNonNullableByDefault*/;
//
// Problems in library:
//
// pkg/front_end/testcases/nnbd/issue42089.dart:7:16: Error: A value of type 'X?' can't be assigned to a variable of type 'Object'.
// - 'Object' is from 'dart:core'.
// Object o = x;
// ^
//
// pkg/front_end/testcases/nnbd/issue42089.dart:8:9: Error: A value of type 'X?' can't be assigned to a variable of type 'Object'.
// - 'Object' is from 'dart:core'.
// o = x;
// ^
//
import self as self;
import "dart:core" as core;

static method test<X extends core::Object? = dynamic>(self::test::X? x) → dynamic {
if(x is{ForNonNullableByDefault} core::String?) {
core::Object o = let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/nnbd/issue42089.dart:7:16: Error: A value of type 'X?' can't be assigned to a variable of type 'Object'.
- 'Object' is from 'dart:core'.
Object o = x;
^" in x{self::test::X? & core::String? /* '?' & '?' = '?' */} as{TypeError,ForNonNullableByDefault} core::Object;
o = let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/nnbd/issue42089.dart:8:9: Error: A value of type 'X?' can't be assigned to a variable of type 'Object'.
- 'Object' is from 'dart:core'.
o = x;
^" in x{self::test::X? & core::String? /* '?' & '?' = '?' */} as{TypeError,ForNonNullableByDefault} core::Object;
}
}
static method main() → dynamic {}
@@ -0,0 +1,30 @@
library /*isNonNullableByDefault*/;
//
// Problems in library:
//
// pkg/front_end/testcases/nnbd/issue42089.dart:7:16: Error: A value of type 'X?' can't be assigned to a variable of type 'Object'.
// - 'Object' is from 'dart:core'.
// Object o = x;
// ^
//
// pkg/front_end/testcases/nnbd/issue42089.dart:8:9: Error: A value of type 'X?' can't be assigned to a variable of type 'Object'.
// - 'Object' is from 'dart:core'.
// o = x;
// ^
//
import self as self;
import "dart:core" as core;

static method test<X extends core::Object? = dynamic>(self::test::X? x) → dynamic {
if(x is{ForNonNullableByDefault} core::String?) {
core::Object o = let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/nnbd/issue42089.dart:7:16: Error: A value of type 'X?' can't be assigned to a variable of type 'Object'.
- 'Object' is from 'dart:core'.
Object o = x;
^" in x{self::test::X? & core::String? /* '?' & '?' = '?' */};
o = let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/nnbd/issue42089.dart:8:9: Error: A value of type 'X?' can't be assigned to a variable of type 'Object'.
- 'Object' is from 'dart:core'.
o = x;
^" in x{self::test::X? & core::String? /* '?' & '?' = '?' */};
}
}
static method main() → dynamic {}
31 changes: 31 additions & 0 deletions pkg/front_end/testcases/nnbd_mixed/type_parameter_nullability.dart
@@ -0,0 +1,31 @@
// 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.

import 'type_parameter_nullability_lib.dart';

class C<T extends num?, S, U> {
void promoteNullable(T? t) {
if (t is int) /* Creates T? & int! */ {
t;
}
if (t is int?) /* Creates T? & int? */ {
t;
}
}

void nullableAsUndetermined(S? s) {
s as U; /* Creates S? & U% */
}
}

main() {
var c = new C<num, num, num>();
c.promoteNullable(null);
c.promoteNullable(0);
c.nullableAsUndetermined(null);
c.nullableAsUndetermined(0);
var d = new D<num>();
d.promoteLegacy(null);
d.promoteLegacy(0);
}
@@ -0,0 +1,8 @@
import 'type_parameter_nullability_lib.dart';

class C<T extends num?, S, U> {
void promoteNullable(T? t) {}
void nullableAsUndetermined(S? s) {}
}

main() {}
@@ -0,0 +1,8 @@
import 'type_parameter_nullability_lib.dart';

class C<T extends num?, S, U> {
void nullableAsUndetermined(S? s) {}
void promoteNullable(T? t) {}
}

main() {}
@@ -0,0 +1,58 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
import "type_parameter_nullability_lib.dart" as typ;

import "org-dartlang-testcase:///type_parameter_nullability_lib.dart";

class C<T extends core::num? = core::num?, S extends core::Object? = dynamic, U extends core::Object? = dynamic> extends core::Object {
synthetic constructor •() → self::C<self::C::T%, self::C::S%, self::C::U%>
: super core::Object::•()
;
method promoteNullable(generic-covariant-impl self::C::T? t) → void {
if(t is{ForNonNullableByDefault} core::int) {
t{self::C::T? & core::int /* '?' & '!' = '!' */};
}
if(t is{ForNonNullableByDefault} core::int?) {
t{self::C::T? & core::int? /* '?' & '?' = '?' */};
}
}
method nullableAsUndetermined(generic-covariant-impl self::C::S? s) → void {
s as{ForNonNullableByDefault} self::C::U%;
}
}
static method main() → dynamic {
self::C<core::num, core::num, core::num> c = new self::C::•<core::num, core::num, core::num>();
c.{self::C::promoteNullable}(null);
c.{self::C::promoteNullable}(0);
c.{self::C::nullableAsUndetermined}(null);
c.{self::C::nullableAsUndetermined}(0);
typ::D<core::num> d = new typ::D::•<core::num>();
d.{typ::D::promoteLegacy}(null);
d.{typ::D::promoteLegacy}(0);
}

library;
import self as typ;
import "dart:core" as core;

class D<T extends core::num* = core::num*> extends core::Object {
synthetic constructor •() → typ::D<typ::D::T*>*
: super core::Object::•()
;
method promoteLegacy(generic-covariant-impl typ::D::T* t) → void {
if(t is core::int*) {
let final typ::D::T* & core::int* /* '*' & '*' = '*' */ #t1 = t{typ::D::T* & core::int* /* '*' & '*' = '*' */} in #t1.{core::num::==}(null) ?{core::bool*} null : #t1.{core::int::isEven};
}
}
abstract member-signature get _identityHashCode() → core::int*;
abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*;
abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*;
abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*;
abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*;
abstract member-signature operator ==(dynamic other) → core::bool*;
abstract member-signature get hashCode() → core::int*;
abstract member-signature method toString() → core::String*;
abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic;
abstract member-signature get runtimeType() → core::Type*;
}
@@ -0,0 +1,58 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
import "type_parameter_nullability_lib.dart" as typ;

import "org-dartlang-testcase:///type_parameter_nullability_lib.dart";

class C<T extends core::num? = core::num?, S extends core::Object? = dynamic, U extends core::Object? = dynamic> extends core::Object {
synthetic constructor •() → self::C<self::C::T%, self::C::S%, self::C::U%>
: super core::Object::•()
;
method promoteNullable(generic-covariant-impl self::C::T? t) → void {
if(t is{ForNonNullableByDefault} core::int) {
t{self::C::T? & core::int /* '?' & '!' = '!' */};
}
if(t is{ForNonNullableByDefault} core::int?) {
t{self::C::T? & core::int? /* '?' & '?' = '?' */};
}
}
method nullableAsUndetermined(generic-covariant-impl self::C::S? s) → void {
s as{ForNonNullableByDefault} self::C::U%;
}
}
static method main() → dynamic {
self::C<core::num, core::num, core::num> c = new self::C::•<core::num, core::num, core::num>();
c.{self::C::promoteNullable}(null);
c.{self::C::promoteNullable}(0);
c.{self::C::nullableAsUndetermined}(null);
c.{self::C::nullableAsUndetermined}(0);
typ::D<core::num> d = new typ::D::•<core::num>();
d.{typ::D::promoteLegacy}(null);
d.{typ::D::promoteLegacy}(0);
}

library;
import self as typ;
import "dart:core" as core;

class D<T extends core::num* = core::num*> extends core::Object {
synthetic constructor •() → typ::D<typ::D::T*>*
: super core::Object::•()
;
method promoteLegacy(generic-covariant-impl typ::D::T* t) → void {
if(t is core::int*) {
let final typ::D::T* & core::int* /* '*' & '*' = '*' */ #t1 = t{typ::D::T* & core::int* /* '*' & '*' = '*' */} in #t1.{core::num::==}(null) ?{core::bool*} null : #t1.{core::int::isEven};
}
}
abstract member-signature get _identityHashCode() → core::int*;
abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*;
abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*;
abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*;
abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*;
abstract member-signature operator ==(dynamic other) → core::bool*;
abstract member-signature get hashCode() → core::int*;
abstract member-signature method toString() → core::String*;
abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic;
abstract member-signature get runtimeType() → core::Type*;
}
@@ -0,0 +1,13 @@
// 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.6

class D<T extends num> {
void promoteLegacy(T t) {
if (t is int) {
t?.isEven; // Creates T* & int!
}
}
}

0 comments on commit 5d1fbe0

Please sign in to comment.