| 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;
 | 
|  
 | 
| 
 |