Index: pkg/front_end/lib/src/fasta/scope.dart |
diff --git a/pkg/front_end/lib/src/fasta/scope.dart b/pkg/front_end/lib/src/fasta/scope.dart |
index c477ba95b303735a04e833cdc9f809eb24970cf6..2dd1656ef0bf633fb525fc4f7574981daa07c032 100644 |
--- a/pkg/front_end/lib/src/fasta/scope.dart |
+++ b/pkg/front_end/lib/src/fasta/scope.dart |
@@ -4,21 +4,25 @@ |
library fasta.scope; |
-import 'builder/builder.dart' show Builder, MixedAccessor; |
+import 'builder/builder.dart' show Builder, TypeVariableBuilder; |
import 'errors.dart' show internalError; |
-class Scope { |
+class MutableScope { |
/// Names declared in this scope. |
- final Map<String, Builder> local; |
+ Map<String, Builder> local; |
/// Setters declared in this scope. |
- final Map<String, Builder> setters; |
+ Map<String, Builder> setters; |
/// The scope that this scope is nested within, or `null` if this is the top |
/// level scope. |
- final Scope parent; |
+ Scope parent; |
+ MutableScope(this.local, this.setters, this.parent); |
+} |
+ |
+class Scope extends MutableScope { |
/// Indicates whether an attempt to declare new names in this scope should |
/// succeed. |
final bool isModifiable; |
@@ -27,9 +31,9 @@ class Scope { |
Map<String, Builder> forwardDeclaredLabels; |
- Scope(this.local, Map<String, Builder> setters, this.parent, |
+ Scope(Map<String, Builder> local, Map<String, Builder> setters, Scope parent, |
{this.isModifiable: true}) |
- : setters = setters ?? const <String, Builder>{}; |
+ : super(local, setters = setters ?? const <String, Builder>{}, parent); |
Scope.top({bool isModifiable: false}) |
: this(<String, Builder>{}, <String, Builder>{}, null, |
@@ -42,10 +46,38 @@ class Scope { |
Scope.nested(Scope parent, {bool isModifiable: true}) |
: this(<String, Builder>{}, null, parent, isModifiable: isModifiable); |
+ /// Don't use this. Use [becomePartOf] instead. |
+ void set local(_) => internalError("Unsupported operation."); |
+ |
+ /// Don't use this. Use [becomePartOf] instead. |
+ void set setters(_) => internalError("Unsupported operation."); |
+ |
+ /// Don't use this. Use [becomePartOf] instead. |
+ void set parent(_) => internalError("Unsupported operation."); |
+ |
+ /// This scope becomes equivalent to [scope]. This is used for parts to |
+ /// become part of their library's scope. |
+ void becomePartOf(Scope scope) { |
+ assert(parent.parent == null); |
+ assert(scope.parent.parent == null); |
+ super.local = scope.local; |
+ super.setters = scope.setters; |
+ super.parent = scope.parent; |
+ } |
+ |
Scope createNestedScope({bool isModifiable: true}) { |
return new Scope.nested(this, isModifiable: isModifiable); |
} |
+ Scope withTypeVariables(List<TypeVariableBuilder> typeVariables) { |
+ if (typeVariables == null) return this; |
+ Scope newScope = new Scope.nested(this, isModifiable: false); |
+ for (TypeVariableBuilder t in typeVariables) { |
+ newScope.local[t.name] = t; |
+ } |
+ return newScope; |
+ } |
+ |
/// Create a special scope for use by labeled staments. This scope doesn't |
/// introduce a new scope for local variables, only for labels. This deals |
/// with corner cases like this: |
@@ -57,66 +89,49 @@ class Scope { |
return new Scope(local, setters, parent, isModifiable: true); |
} |
- Builder lookup(String name, int charOffset, Uri fileUri, |
- {bool isInstanceScope: true}) { |
- Builder builder = local[name]; |
- if (builder != null) { |
- if (builder.next != null) { |
- return lookupAmbiguous(name, builder, false, charOffset, fileUri); |
- } |
- return builder.isSetter |
- ? new AccessErrorBuilder(name, builder, charOffset, fileUri) |
- : builder; |
+ Builder lookupIn(String name, int charOffset, Uri fileUri, |
+ Map<String, Builder> map, bool isInstanceScope) { |
+ Builder builder = map[name]; |
+ if (builder == null) return null; |
+ if (builder.next != null) { |
+ return new AmbiguousBuilder(name, builder, charOffset, fileUri); |
+ } else if (!isInstanceScope && builder.isInstanceMember) { |
+ return null; |
} else { |
- return parent?.lookup(name, charOffset, fileUri); |
+ return builder; |
} |
} |
- Builder lookupSetter(String name, int charOffset, Uri fileUri, |
+ Builder lookup(String name, int charOffset, Uri fileUri, |
{bool isInstanceScope: true}) { |
- Builder builder = local[name]; |
- if (builder != null) { |
- if (builder.next != null) { |
- return lookupAmbiguous(name, builder, true, charOffset, fileUri); |
- } |
- if (builder.isField) { |
- if (builder.isFinal) { |
- return new AccessErrorBuilder(name, builder, charOffset, fileUri); |
- } else { |
- return builder; |
- } |
- } else if (builder.isSetter) { |
- return builder; |
- } else { |
- return new AccessErrorBuilder(name, builder, charOffset, fileUri); |
- } |
- } else { |
- return parent?.lookupSetter(name, charOffset, fileUri); |
+ Builder builder = |
+ lookupIn(name, charOffset, fileUri, local, isInstanceScope); |
+ if (builder != null) return builder; |
+ builder = lookupIn(name, charOffset, fileUri, setters, isInstanceScope); |
+ if (builder != null && !builder.hasProblem) { |
+ return new AccessErrorBuilder(name, builder, charOffset, fileUri); |
} |
+ if (!isInstanceScope) { |
+ // For static lookup, do not seach the parent scope. |
+ return builder; |
+ } |
+ return builder ?? parent?.lookup(name, charOffset, fileUri); |
} |
- Builder lookupAmbiguous( |
- String name, Builder builder, bool setter, int charOffset, Uri fileUri) { |
- assert(builder.next != null); |
- if (builder is MixedAccessor) { |
- return setter ? builder.setter : builder.getter; |
+ Builder lookupSetter(String name, int charOffset, Uri fileUri, |
+ {bool isInstanceScope: true}) { |
+ Builder builder = |
+ lookupIn(name, charOffset, fileUri, setters, isInstanceScope); |
+ if (builder != null) return builder; |
+ builder = lookupIn(name, charOffset, fileUri, local, isInstanceScope); |
+ if (builder != null && !builder.hasProblem) { |
+ return new AccessErrorBuilder(name, builder, charOffset, fileUri); |
} |
- Builder setterBuilder; |
- Builder getterBuilder; |
- Builder current = builder; |
- while (current != null) { |
- if (current.isGetter && getterBuilder == null) { |
- getterBuilder = current; |
- } else if (current.isSetter && setterBuilder == null) { |
- setterBuilder = current; |
- } else { |
- return new AmbiguousBuilder(name, builder, charOffset, fileUri); |
- } |
- current = current.next; |
+ if (!isInstanceScope) { |
+ // For static lookup, do not seach the parent scope. |
+ return builder; |
} |
- assert(getterBuilder != null); |
- assert(setterBuilder != null); |
- return setter ? setterBuilder : getterBuilder; |
+ return builder ?? parent?.lookupSetter(name, charOffset, fileUri); |
} |
bool hasLocalLabel(String name) => labels != null && labels.containsKey(name); |
@@ -161,8 +176,28 @@ class Scope { |
} |
} |
+ void merge(Scope scope, |
+ buildAmbiguousBuilder(String name, Builder existing, Builder member)) { |
+ Map<String, Builder> map = local; |
+ |
+ void mergeMember(String name, Builder member) { |
+ Builder existing = map[name]; |
+ if (existing != null) { |
+ if (existing != member) { |
+ member = buildAmbiguousBuilder(name, existing, member); |
+ } |
+ } |
+ map[name] = member; |
+ } |
+ |
+ scope.local.forEach(mergeMember); |
+ map = setters; |
+ scope.setters.forEach(mergeMember); |
+ } |
+ |
void forEach(f(String name, Builder member)) { |
local.forEach(f); |
+ setters.forEach(f); |
} |
String get debugString { |
@@ -188,6 +223,22 @@ class Scope { |
} |
} |
+class ScopeBuilder { |
+ final Scope scope; |
+ |
+ ScopeBuilder(this.scope); |
+ |
+ void addMember(String name, Builder builder) { |
+ scope.local[name] = builder; |
+ } |
+ |
+ void addSetter(String name, Builder builder) { |
+ scope.setters[name] = builder; |
+ } |
+ |
+ Builder operator [](String name) => scope.local[name]; |
+} |
+ |
abstract class ProblemBuilder extends Builder { |
final String name; |