Index: pkg/compiler/lib/src/inferrer/locals_handler.dart |
diff --git a/pkg/compiler/lib/src/inferrer/locals_handler.dart b/pkg/compiler/lib/src/inferrer/locals_handler.dart |
index afdbea2b7665fef5c582cf3b7f256032034d49e4..014b0613b5d1926159387025bf19e111b2812574 100644 |
--- a/pkg/compiler/lib/src/inferrer/locals_handler.dart |
+++ b/pkg/compiler/lib/src/inferrer/locals_handler.dart |
@@ -102,16 +102,24 @@ class VariableScope { |
} |
} |
+/// Tracks initializers via initializations and assignments. |
class FieldInitializationScope { |
final TypeSystem types; |
Map<Element, TypeInformation> fields; |
bool isThisExposed; |
- FieldInitializationScope(this.types) : isThisExposed = false; |
+ /// `true` when control flow prevents accumulating definite assignments, |
+ /// e.g. an early return or caught exception. |
+ bool isIndefinite; |
+ |
+ FieldInitializationScope(this.types) |
+ : isThisExposed = false, |
+ isIndefinite = false; |
FieldInitializationScope.internalFrom(FieldInitializationScope other) |
: types = other.types, |
- isThisExposed = other.isThisExposed; |
+ isThisExposed = other.isThisExposed, |
+ isIndefinite = other.isIndefinite; |
factory FieldInitializationScope.from(FieldInitializationScope other) { |
if (other == null) return null; |
@@ -120,7 +128,8 @@ class FieldInitializationScope { |
void updateField(Element field, TypeInformation type) { |
if (isThisExposed) return; |
- if (fields == null) fields = new Map<Element, TypeInformation>(); |
+ if (isIndefinite) return; |
+ fields ??= new Map<Element, TypeInformation>(); |
fields[field] = type; |
} |
@@ -129,25 +138,27 @@ class FieldInitializationScope { |
} |
void forEach(void f(Element element, TypeInformation type)) { |
- if (fields == null) return; |
- fields.forEach(f); |
+ fields?.forEach(f); |
} |
void mergeDiamondFlow( |
FieldInitializationScope thenScope, FieldInitializationScope elseScope) { |
- // Quick bailout check. If [isThisExposed] is true, we know the |
- // code following won'TypeInformation do anything. |
+ // Quick bailout check. If [isThisExposed] or [isIndefinite] is true, we |
+ // know the code following won'TypeInformation do anything. |
if (isThisExposed) return; |
- if (elseScope == null || elseScope.fields == null) { |
- elseScope = this; |
- } |
+ if (isIndefinite) return; |
+ |
+ FieldInitializationScope otherScope = |
+ (elseScope == null || elseScope.fields == null) ? this : elseScope; |
thenScope.forEach((Element field, TypeInformation type) { |
- TypeInformation otherType = elseScope.readField(field); |
+ TypeInformation otherType = otherScope.readField(field); |
if (otherType == null) return; |
updateField(field, types.allocateDiamondPhi(type, otherType)); |
}); |
+ |
isThisExposed = thenScope.isThisExposed || elseScope.isThisExposed; |
+ isIndefinite = thenScope.isIndefinite || elseScope.isIndefinite; |
} |
} |