Skip to content

Commit

Permalink
Version 2.10.0-110.3.beta
Browse files Browse the repository at this point in the history
* Cherry-pick 8d68480 to beta
* Cherry-pick afc2778 to beta
  • Loading branch information
athomas committed Sep 15, 2020
2 parents 3f787d6 + 46ba446 commit 52130c1
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ class TextDocumentOpenHandler
);
server.onOverlayCreated(path, doc.text);

final driver = server.contextManager.getDriverFor(path);
final driver = server.getAnalysisDriver(path);
// If the file did not exist, and is "overlay only", it still should be
// analyzed. Add it to driver to which it should have been added.

Expand Down
37 changes: 37 additions & 0 deletions pkg/analysis_server/test/lsp/change_workspace_folders_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,43 @@ class ChangeWorkspaceFoldersTest extends AbstractLspAnalysisServerTest {
);
}

Future<void> test_changeWorkspaceFolders_openFileOutsideRoot() async {
// When a file is opened that is outside of the analysis roots, the first
// analysis driver will be used (see [AbstractAnalysisServer.getAnalysisDriver]).
// This means as long as there is already an analysis root, the implicit root
// will be the original root and not the path of the opened file.
// For example, Go-to-Definition into a file in PubCache must *not* result in
// the pub cache folder being added as an analysis root, it should be analyzed
// by the existing project's driver.
final workspace1FilePath = join(workspaceFolder1Path, 'test.dart');
await newFile(workspace1FilePath);
final workspace2FilePath = join(workspaceFolder2Path, 'test.dart');
final workspace2FileUri = Uri.file(workspace2FilePath);
await newFile(workspace2FilePath);

await initialize(workspaceFolders: [workspaceFolder1Uri]);

// Expect explicit root for the workspace folder.
expect(
server.contextManager.includedPaths,
unorderedEquals([workspaceFolder1Path]),
);

// Open a file in workspaceFolder2 (which is not in the analysis roots).
await openFile(workspace2FileUri, '');
expect(
server.contextManager.includedPaths,
unorderedEquals([workspaceFolder1Path]),
);

// Closing the file should not result in the project being removed.
await closeFile(workspace2FileUri);
expect(
server.contextManager.includedPaths,
unorderedEquals([workspaceFolder1Path]),
);
}

Future<void> test_changeWorkspaceFolders_remove() async {
await initialize(
workspaceFolders: [workspaceFolder1Uri, workspaceFolder2Uri],
Expand Down
47 changes: 26 additions & 21 deletions pkg/compiler/lib/src/inferrer/builder_kernel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -983,10 +983,11 @@ class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation> {
if (variable != null) {
Local local = _localsMap.getLocalVariable(variable);
if (!_capturedVariables.contains(local)) {
// Receiver strengthening to non-null.
DartType type = _localsMap.getLocalType(_elementMap, local);
_state.updateLocal(
_inferrer, _capturedAndBoxed, local, receiverType, node, type,
isNullable: selector.appliesToNullWithoutThrow());
excludeNull: !selector.appliesToNullWithoutThrow());
}
}

Expand Down Expand Up @@ -1445,11 +1446,16 @@ class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation> {
ir.Expression operand = node.operand;
if (operand is ir.VariableGet) {
Local local = _localsMap.getLocalVariable(operand.variable);
DartType type = _elementMap.getDartType(node.type);
DartType localType = _elementMap.getDartType(node.type);
LocalState stateAfterCheckWhenTrue = new LocalState.childPath(_state);
LocalState stateAfterCheckWhenFalse = new LocalState.childPath(_state);
stateAfterCheckWhenTrue.narrowLocal(
_inferrer, _capturedAndBoxed, local, type, node);

// Narrow variable to tested type on true branch.
TypeInformation currentTypeInformation = stateAfterCheckWhenTrue
.readLocal(_inferrer, _capturedAndBoxed, local);
stateAfterCheckWhenTrue.updateLocal(_inferrer, _capturedAndBoxed, local,
currentTypeInformation, node, localType,
isCast: false);
_setStateAfter(_state, stateAfterCheckWhenTrue, stateAfterCheckWhenFalse);
}
}
Expand All @@ -1462,10 +1468,18 @@ class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation> {
DartType localType = _localsMap.getLocalType(_elementMap, local);
LocalState stateAfterCheckWhenTrue = new LocalState.childPath(_state);
LocalState stateAfterCheckWhenFalse = new LocalState.childPath(_state);

// Narrow tested variable to 'Null' on true branch.
stateAfterCheckWhenTrue.updateLocal(_inferrer, _capturedAndBoxed, local,
_types.nullType, node, localType);
stateAfterCheckWhenFalse.narrowLocal(_inferrer, _capturedAndBoxed, local,
_closedWorld.commonElements.objectType, node);

// Narrow tested variable to 'not null' on false branch.
TypeInformation currentTypeInformation = stateAfterCheckWhenFalse
.readLocal(_inferrer, _capturedAndBoxed, local);
stateAfterCheckWhenFalse.updateLocal(_inferrer, _capturedAndBoxed, local,
currentTypeInformation, node, _closedWorld.commonElements.objectType,
excludeNull: true);

_setStateAfter(_state, stateAfterCheckWhenTrue, stateAfterCheckWhenFalse);
}
}
Expand Down Expand Up @@ -1620,7 +1634,7 @@ class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation> {
DartType type = _localsMap.getLocalType(_elementMap, local);
_state.updateLocal(
_inferrer, _capturedAndBoxed, local, localFunctionType, node, type,
isNullable: false);
excludeNull: true);
}

// We don't put the closure in the work queue of the
Expand Down Expand Up @@ -1737,7 +1751,7 @@ class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation> {
Local local = _localsMap.getLocalVariable(exception);
_state.updateLocal(_inferrer, _capturedAndBoxed, local, mask, node,
_dartTypes.dynamicType(),
isNullable: false /* `throw null` produces a NullThrownError */);
excludeNull: true /* `throw null` produces a NullThrownError */);
}
ir.VariableDeclaration stackTrace = node.stackTrace;
if (stackTrace != null) {
Expand Down Expand Up @@ -2088,9 +2102,11 @@ class LocalState {
TypeInformation type,
ir.Node node,
DartType staticType,
{isNullable: true}) {
{isCast: true,
excludeNull: false}) {
assert(type != null);
type = inferrer.types.narrowType(type, staticType, isNullable: isNullable);
type = inferrer.types
.narrowType(type, staticType, isCast: isCast, excludeNull: excludeNull);

FieldEntity field = capturedAndBoxed[local];
if (field != null) {
Expand All @@ -2100,17 +2116,6 @@ class LocalState {
}
}

void narrowLocal(
InferrerEngine inferrer,
Map<Local, FieldEntity> capturedAndBoxed,
Local local,
DartType type,
ir.Node node) {
TypeInformation currentType = readLocal(inferrer, capturedAndBoxed, local);
updateLocal(inferrer, capturedAndBoxed, local, currentType, node, type,
isNullable: false);
}

LocalState mergeFlow(InferrerEngine inferrer, LocalState other) {
seenReturnOrThrow = false;
seenBreakOrContinue = false;
Expand Down
63 changes: 30 additions & 33 deletions pkg/compiler/lib/src/inferrer/type_system.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import '../common.dart';
import '../constants/values.dart' show BoolConstantValue;
import '../elements/entities.dart';
import '../elements/types.dart';
import '../ir/static_type.dart' show ClassRelation;
import '../world.dart';
import 'abstract_value_domain.dart';
import 'type_graph_nodes.dart';
Expand Down Expand Up @@ -332,46 +333,42 @@ class TypeSystem {
_abstractValueDomain.isNull(type.typeAnnotation).isDefinitelyFalse;

/// Returns the intersection between [type] and [annotation].
/// [isNullable] indicates whether the annotation implies a null
/// type.
///
/// [isCast] indicates whether narrowing comes from a cast or parameter check
/// rather than an 'is' test. (In legacy semantics these differ on whether
/// `null` is accepted).
///
/// If [excludeNull] is true, the intersection excludes `null` even if the
/// Dart type implies `null`.
TypeInformation narrowType(TypeInformation type, DartType annotation,
{bool isNullable: true}) {
TypeInformation _narrowTo(AbstractValue otherType) {
if (_abstractValueDomain.isExact(type.type).isDefinitelyTrue) return type;
if (isNullable) {
otherType = _abstractValueDomain.includeNull(otherType);
}
TypeInformation newType =
new NarrowTypeInformation(_abstractValueDomain, type, otherType);
allocatedTypes.add(newType);
return newType;
{bool isCast: true, bool excludeNull: false}) {
// Avoid refining an input with an exact type. It we are almost always
// adding a narrowing to a subtype of the same class or a superclass.
if (_abstractValueDomain.isExact(type.type).isDefinitelyTrue) return type;

AbstractValueWithPrecision narrowing =
_abstractValueDomain.createFromStaticType(annotation,
classRelation: ClassRelation.subtype, nullable: isCast);

AbstractValue abstractValue = narrowing.abstractValue;
if (excludeNull) {
abstractValue = _abstractValueDomain.excludeNull(abstractValue);
}

// TODO(fishythefish): Use nullability.
annotation = annotation.withoutNullability;
if (annotation is VoidType) return type;
if (_closedWorld.dartTypes.isTopType(annotation)) {
if (isNullable) return type;
if (_abstractValueDomain.containsAll(abstractValue).isPotentiallyTrue) {
// Top, or non-nullable Top.
if (_abstractValueDomain.isNull(abstractValue).isPotentiallyTrue) {
return type;
}
// If the input is already narrowed to be not-null, there is no value
// in adding another narrowing node.
if (_isNonNullNarrow(type)) return type;
return _narrowTo(_abstractValueDomain.excludeNull(dynamicType.type));
} else if (annotation is NeverType) {
return _narrowTo(_abstractValueDomain.emptyType);
} else if (annotation is InterfaceType) {
return _narrowTo(
_abstractValueDomain.createNonNullSubtype(annotation.element));
} else if (annotation is FunctionType) {
return _narrowTo(functionType.type);
} else if (annotation is FutureOrType) {
// TODO(johnniwinther): Support narrowing of FutureOr.
return type;
} else if (annotation is TypeVariableType) {
// TODO(ngeoffray): Narrow to bound.
return type;
} else {
throw 'Unexpected annotation type $annotation';
}

TypeInformation newType =
NarrowTypeInformation(_abstractValueDomain, type, abstractValue);
allocatedTypes.add(newType);
return newType;
}

ParameterTypeInformation getInferredTypeOfParameter(Local parameter) {
Expand Down
3 changes: 1 addition & 2 deletions pkg/compiler/test/analyses/api_allowed.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@
"Dynamic access of 'dart.collection::_modifications'.": 5,
"Dynamic access of 'dart.collection::_map'.": 4,
"Dynamic access of 'dart.collection::_elements'.": 1,
"Dynamic access of 'dart.collection::_element'.": 1,
"Dynamic access of 'dart.collection::_first'.": 1
},
"org-dartlang-sdk:///lib/html/dart2js/html_dart2js.dart": {
Expand Down Expand Up @@ -198,4 +197,4 @@
"org-dartlang-sdk:///lib/_http/websocket_impl.dart": {
"Dynamic invocation of 'dart._http::_toJSON'.": 1
}
}
}
10 changes: 5 additions & 5 deletions sdk/lib/_internal/js_runtime/lib/collection_patch.dart
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ class _HashMap<K, V> extends MapBase<K, V> implements HashMap<K, V> {
JS('void', 'delete #[#]', table, key);
}

List _getBucket(var table, var key) {
List? _getBucket(var table, var key) {
var hash = _computeHashCode(key);
return JS('var', '#[#]', table, hash);
}
Expand Down Expand Up @@ -905,7 +905,7 @@ class _HashSet<E> extends _SetBase<E> implements HashSet<E> {
var bucket = _getBucket(rest, object);
var index = _findBucketIndex(bucket, object);
if (index < 0) return null;
return bucket[index];
return JS('', '#[#]', bucket, index);
}

// Collection.
Expand Down Expand Up @@ -1091,7 +1091,7 @@ class _HashSet<E> extends _SetBase<E> implements HashSet<E> {
JS('void', 'delete #[#]', table, key);
}

List _getBucket(var table, var element) {
List? _getBucket(var table, var element) {
var hash = _computeHashCode(element);
return JS('var', '#[#]', table, hash);
}
Expand Down Expand Up @@ -1357,7 +1357,7 @@ class _LinkedHashSet<E> extends _SetBase<E> implements LinkedHashSet<E> {
var bucket = _getBucket(rest, object);
var index = _findBucketIndex(bucket, object);
if (index < 0) return null;
return bucket[index]._element;
return JS<_LinkedHashSetCell>('', '#[#]', bucket, index)._element;
}

void forEach(void action(E element)) {
Expand Down Expand Up @@ -1564,7 +1564,7 @@ class _LinkedHashSet<E> extends _SetBase<E> implements LinkedHashSet<E> {
JS('void', 'delete #[#]', table, key);
}

List _getBucket(var table, var element) {
List? _getBucket(var table, var element) {
var hash = _computeHashCode(element);
return JS('var', '#[#]', table, hash);
}
Expand Down
28 changes: 28 additions & 0 deletions tests/language/regress/regress43366_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// 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.

String upcase(String? s) {
if (s == null) return '';
return s.toUpperCase();
}

String format(dynamic thing) {
if (thing is String?) return upcase(thing);
if (thing is num) return '$thing';
return '?';
}

main() {
log(format(null));
log(format('hello'));
log(format([]));

if (trace != '[][HELLO][?]') throw 'Unexpected: "$trace"';
}

String trace = '';

void log(String s) {
trace += '[$s]';
}
2 changes: 1 addition & 1 deletion tools/VERSION
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@ MAJOR 2
MINOR 10
PATCH 0
PRERELEASE 110
PRERELEASE_PATCH 1
PRERELEASE_PATCH 3

0 comments on commit 52130c1

Please sign in to comment.