Skip to content

Commit

Permalink
[cfe] Gather constraints from both possibilities for FutureOr
Browse files Browse the repository at this point in the history
Closes flutter#37778.

Bug: http://dartbug.com/37778.
Change-Id: Ia8828c27ccc912831a0fea8a473c547184c99229
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/115243
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Dmitry Stefantsov <dmitryas@google.com>
  • Loading branch information
Dmitry Stefantsov authored and commit-bot@chromium.org committed Sep 10, 2019
1 parent f1f709e commit ccb6ba9
Show file tree
Hide file tree
Showing 8 changed files with 109 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -259,12 +259,6 @@ abstract class TypeConstraintGatherer {
// identical(). If P and Q are equal but not identical, recursing through
// the types will give the proper result.
if (identical(subtype, supertype)) return true;
// Any type `P` is a subtype match for `dynamic`, `Object`, or `void` under
// no constraints.
if (_isTop(supertype)) return true;
// `Null` is a subtype match for any type `Q` under no constraints.
// Note that nullable types will change this.
if (_isNull(subtype)) return true;

// Handle FutureOr<T> union type.
if (subtype is InterfaceType &&
Expand Down Expand Up @@ -302,11 +296,34 @@ abstract class TypeConstraintGatherer {
// - And `P` is a subtype match for `Q` with respect to `L` under
// constraints `C`
DartType supertypeArg = supertype.typeArguments[0];
InterfaceType supertypeFuture = futureType(supertypeArg);
return trySubtypeMatch(subtype, supertypeFuture) ||
_isSubtypeMatch(subtype, supertypeArg);
DartType supertypeFuture = futureType(supertypeArg);

// The outcome of both trySubtypeMatch and _isSubtypeMatch is includes the
// returned boolean value and the added constraints to _protoConstraints.
// Here we need to match 'subtype' against both possibilities of the
// FutureOr<X> which is 'supertype,' that is, we need to match 'subtype'
// against Future<X> and X. However, if the first matching against
// Future<X> finds any new constraints and adds them to _protoConstraints,
// we should prefer them over the constraints possibly found while
// matching against X. Note that if matching against Future<X> returned
// true, but didn't find any new constraints, then matching against X
// should still be done and the new constraints should still be added to
// _protoConstraints.
int oldProtoConstraintsLength = _protoConstraints.length;
bool matchesFuture = trySubtypeMatch(subtype, supertypeFuture);
bool matchesArg = oldProtoConstraintsLength != _protoConstraints.length
? false
: _isSubtypeMatch(subtype, supertypeArg);
return matchesFuture || matchesArg;
}

// Any type `P` is a subtype match for `dynamic`, `Object`, or `void` under
// no constraints.
if (_isTop(supertype)) return true;
// `Null` is a subtype match for any type `Q` under no constraints.
// Note that nullable types will change this.
if (_isNull(subtype)) return true;

// A type variable `T` not in `L` with bound `P` is a subtype match for the
// same type variable `T` with bound `Q` with respect to `L` under
// constraints `C`:
Expand Down
2 changes: 2 additions & 0 deletions pkg/front_end/test/spell_checking_list_common.txt
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ already
also
alternating
alternative
alternatives
alternatively
although
always
Expand Down Expand Up @@ -1984,6 +1985,7 @@ positionals
positions
positive
positives
possibilities
possible
possibly
post
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// 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.

// The test checks the gathering of the constraints during type inference in
// case the supertype of the match is a FutureOr<X> or one of its alternatives
// (either Future<X> or X).

import 'dart:async';

// -----------------------------------------------------------------------------

// Gathering constraints for S from comparison Null <: FutureOr<S>.
void func1() {
void foo<S>(FutureOr<S> bar) {}

/*invoke: void*/ foo/*<Null>*/(/*Null*/ null);
}

// -----------------------------------------------------------------------------

// Gathering constraints for S from comparison Null <: Future<S>.
void func2() {
void foo<S>(Future<S> bar) {}

/*invoke: void*/ foo/*<dynamic>*/(/*Null*/ null);
}

// -----------------------------------------------------------------------------

// Gathering constraints for S from comparison Null <: S.
void func3() {
void foo<S>(S bar) {}

/*invoke: void*/ foo/*<Null>*/(/*Null*/ null);
}

// -----------------------------------------------------------------------------

void func4() {
void foo<S>(FutureOr<FutureOr<S>> bar) {}

/*invoke: void*/ foo/*<Null>*/(/*Null*/ null);
}

// -----------------------------------------------------------------------------

// Gathering constraints for S from comparison int <: FutureOr<S>.
void func5() {
void foo<S>(FutureOr<S> bar) {}

/*invoke: void*/ foo/*<int>*/(/*int*/ 42);
}

// -----------------------------------------------------------------------------

// Gathering constraints for S from comparison int <: S.
void func6() {
void foo<S>(S bar) {}

/*invoke: void*/ foo/*<int>*/(/*int*/ 42);
}

// -----------------------------------------------------------------------------

void func7() {
void foo<S>(FutureOr<FutureOr<S>> bar) {}

/*invoke: void*/ foo/*<int>*/(/*int*/ 42);
}

// -----------------------------------------------------------------------------

main() {}
2 changes: 1 addition & 1 deletion pkg/test_runner/lib/src/process_queue.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1131,7 +1131,7 @@ class BatchRunnerProcess {
}
var processFuture =
io.Process.start(executable, arguments, environment: environment);
processFuture.then((io.Process p) {
processFuture.then<dynamic>((io.Process p) {
_process = p;

Stream<String> _stdoutStream = _process.stdout
Expand Down
2 changes: 1 addition & 1 deletion pkg/test_runner/lib/src/test_case.dart
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ class RunningProcess {
var processFuture = io.Process.start(command.executable, args,
environment: processEnvironment,
workingDirectory: command.workingDirectory);
processFuture.then((io.Process process) {
processFuture.then<dynamic>((io.Process process) {
var stdoutFuture = process.stdout.pipe(stdout);
var stderrFuture = process.stderr.pipe(stderr);
pid = process.pid;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ var tests = <IsolateTest>[
completions.forEach((complete) => complete());

final errors = await Future.wait(results.map((future) {
return future.then((_) {
return future.then<dynamic>((_) {
expect(false, isTrue, reason: 'shouldn\'t get here');
}).catchError((e) => e);
}));
Expand Down
2 changes: 1 addition & 1 deletion tests/lib_2/async/future_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1248,7 +1248,7 @@ class UglyFuture implements Future<dynamic> {
UglyFuture(int badness)
: _result = (badness == 0) ? 42 : new UglyFuture(badness - 1);
Future<S> then<S>(action(value), {Function onError}) {
var c = new Completer();
var c = new Completer<S>();
c.complete(new Future.microtask(() => action(_result)));
return c.future;
}
Expand Down
7 changes: 3 additions & 4 deletions tests/standalone_2/io/server_socket_exception_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,9 @@ void serverSocketExceptionTest() {
Expect.equals(true, !wrongExceptionCaught);

// Test invalid host.
ServerSocket
.bind("__INVALID_HOST__", 0)
.then((server) {})
.catchError((e) => e is SocketException);
ServerSocket.bind("__INVALID_HOST__", 0).then((server) {
Expect.fail('Connection succeeded.');
}).catchError((e) => Expect.isTrue(e is SocketException));
});
}

Expand Down

0 comments on commit ccb6ba9

Please sign in to comment.