Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(876)

Side by Side Diff: pkg/front_end/lib/src/fasta/scope.dart

Issue 2788153002: Create separate scopes for constructors, setters, and other members. (Closed)
Patch Set: One more flaky standalone/io test. Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library fasta.scope; 5 library fasta.scope;
6 6
7 import 'builder/builder.dart' show Builder, MixedAccessor; 7 import 'builder/builder.dart' show Builder, TypeVariableBuilder;
8 8
9 import 'errors.dart' show internalError; 9 import 'errors.dart' show internalError;
10 10
11 class Scope { 11 class MutableScope {
12 /// Names declared in this scope. 12 /// Names declared in this scope.
13 final Map<String, Builder> local; 13 Map<String, Builder> local;
14 14
15 /// Setters declared in this scope. 15 /// Setters declared in this scope.
16 final Map<String, Builder> setters; 16 Map<String, Builder> setters;
17 17
18 /// The scope that this scope is nested within, or `null` if this is the top 18 /// The scope that this scope is nested within, or `null` if this is the top
19 /// level scope. 19 /// level scope.
20 final Scope parent; 20 Scope parent;
21 21
22 MutableScope(this.local, this.setters, this.parent);
23 }
24
25 class Scope extends MutableScope {
22 /// Indicates whether an attempt to declare new names in this scope should 26 /// Indicates whether an attempt to declare new names in this scope should
23 /// succeed. 27 /// succeed.
24 final bool isModifiable; 28 final bool isModifiable;
25 29
26 Map<String, Builder> labels; 30 Map<String, Builder> labels;
27 31
28 Map<String, Builder> forwardDeclaredLabels; 32 Map<String, Builder> forwardDeclaredLabels;
29 33
30 Scope(this.local, Map<String, Builder> setters, this.parent, 34 Scope(Map<String, Builder> local, Map<String, Builder> setters, Scope parent,
31 {this.isModifiable: true}) 35 {this.isModifiable: true})
32 : setters = setters ?? const <String, Builder>{}; 36 : super(local, setters = setters ?? const <String, Builder>{}, parent);
33 37
34 Scope.top({bool isModifiable: false}) 38 Scope.top({bool isModifiable: false})
35 : this(<String, Builder>{}, <String, Builder>{}, null, 39 : this(<String, Builder>{}, <String, Builder>{}, null,
36 isModifiable: isModifiable); 40 isModifiable: isModifiable);
37 41
38 Scope.immutable() 42 Scope.immutable()
39 : this(const <String, Builder>{}, const <String, Builder>{}, null, 43 : this(const <String, Builder>{}, const <String, Builder>{}, null,
40 isModifiable: false); 44 isModifiable: false);
41 45
42 Scope.nested(Scope parent, {bool isModifiable: true}) 46 Scope.nested(Scope parent, {bool isModifiable: true})
43 : this(<String, Builder>{}, null, parent, isModifiable: isModifiable); 47 : this(<String, Builder>{}, null, parent, isModifiable: isModifiable);
44 48
49 /// Don't use this. Use [becomePartOf] instead.
50 void set local(_) => internalError("Unsupported operation.");
51
52 /// Don't use this. Use [becomePartOf] instead.
53 void set setters(_) => internalError("Unsupported operation.");
54
55 /// Don't use this. Use [becomePartOf] instead.
56 void set parent(_) => internalError("Unsupported operation.");
57
58 /// This scope becomes equivalent to [scope]. This is used for parts to
59 /// become part of their library's scope.
60 void becomePartOf(Scope scope) {
61 assert(parent.parent == null);
62 assert(scope.parent.parent == null);
63 super.local = scope.local;
64 super.setters = scope.setters;
65 super.parent = scope.parent;
66 }
67
45 Scope createNestedScope({bool isModifiable: true}) { 68 Scope createNestedScope({bool isModifiable: true}) {
46 return new Scope.nested(this, isModifiable: isModifiable); 69 return new Scope.nested(this, isModifiable: isModifiable);
47 } 70 }
48 71
72 Scope withTypeVariables(List<TypeVariableBuilder> typeVariables) {
73 if (typeVariables == null) return this;
74 Scope newScope = new Scope.nested(this, isModifiable: false);
75 for (TypeVariableBuilder t in typeVariables) {
76 newScope.local[t.name] = t;
77 }
78 return newScope;
79 }
80
49 /// Create a special scope for use by labeled staments. This scope doesn't 81 /// Create a special scope for use by labeled staments. This scope doesn't
50 /// introduce a new scope for local variables, only for labels. This deals 82 /// introduce a new scope for local variables, only for labels. This deals
51 /// with corner cases like this: 83 /// with corner cases like this:
52 /// 84 ///
53 /// L: var x; 85 /// L: var x;
54 /// x = 42; 86 /// x = 42;
55 /// print("The answer is $x."); 87 /// print("The answer is $x.");
56 Scope createNestedLabelScope() { 88 Scope createNestedLabelScope() {
57 return new Scope(local, setters, parent, isModifiable: true); 89 return new Scope(local, setters, parent, isModifiable: true);
58 } 90 }
59 91
92 Builder lookupIn(String name, int charOffset, Uri fileUri,
93 Map<String, Builder> map, bool isInstanceScope) {
94 Builder builder = map[name];
95 if (builder == null) return null;
96 if (builder.next != null) {
97 return new AmbiguousBuilder(name, builder, charOffset, fileUri);
98 } else if (!isInstanceScope && builder.isInstanceMember) {
99 return null;
100 } else {
101 return builder;
102 }
103 }
104
60 Builder lookup(String name, int charOffset, Uri fileUri, 105 Builder lookup(String name, int charOffset, Uri fileUri,
61 {bool isInstanceScope: true}) { 106 {bool isInstanceScope: true}) {
62 Builder builder = local[name]; 107 Builder builder =
63 if (builder != null) { 108 lookupIn(name, charOffset, fileUri, local, isInstanceScope);
64 if (builder.next != null) { 109 if (builder != null) return builder;
65 return lookupAmbiguous(name, builder, false, charOffset, fileUri); 110 builder = lookupIn(name, charOffset, fileUri, setters, isInstanceScope);
66 } 111 if (builder != null && !builder.hasProblem) {
67 return builder.isSetter 112 return new AccessErrorBuilder(name, builder, charOffset, fileUri);
68 ? new AccessErrorBuilder(name, builder, charOffset, fileUri)
69 : builder;
70 } else {
71 return parent?.lookup(name, charOffset, fileUri);
72 } 113 }
114 if (!isInstanceScope) {
115 // For static lookup, do not seach the parent scope.
116 return builder;
117 }
118 return builder ?? parent?.lookup(name, charOffset, fileUri);
73 } 119 }
74 120
75 Builder lookupSetter(String name, int charOffset, Uri fileUri, 121 Builder lookupSetter(String name, int charOffset, Uri fileUri,
76 {bool isInstanceScope: true}) { 122 {bool isInstanceScope: true}) {
77 Builder builder = local[name]; 123 Builder builder =
78 if (builder != null) { 124 lookupIn(name, charOffset, fileUri, setters, isInstanceScope);
79 if (builder.next != null) { 125 if (builder != null) return builder;
80 return lookupAmbiguous(name, builder, true, charOffset, fileUri); 126 builder = lookupIn(name, charOffset, fileUri, local, isInstanceScope);
81 } 127 if (builder != null && !builder.hasProblem) {
82 if (builder.isField) { 128 return new AccessErrorBuilder(name, builder, charOffset, fileUri);
83 if (builder.isFinal) {
84 return new AccessErrorBuilder(name, builder, charOffset, fileUri);
85 } else {
86 return builder;
87 }
88 } else if (builder.isSetter) {
89 return builder;
90 } else {
91 return new AccessErrorBuilder(name, builder, charOffset, fileUri);
92 }
93 } else {
94 return parent?.lookupSetter(name, charOffset, fileUri);
95 } 129 }
96 } 130 if (!isInstanceScope) {
97 131 // For static lookup, do not seach the parent scope.
98 Builder lookupAmbiguous( 132 return builder;
99 String name, Builder builder, bool setter, int charOffset, Uri fileUri) {
100 assert(builder.next != null);
101 if (builder is MixedAccessor) {
102 return setter ? builder.setter : builder.getter;
103 } 133 }
104 Builder setterBuilder; 134 return builder ?? parent?.lookupSetter(name, charOffset, fileUri);
105 Builder getterBuilder;
106 Builder current = builder;
107 while (current != null) {
108 if (current.isGetter && getterBuilder == null) {
109 getterBuilder = current;
110 } else if (current.isSetter && setterBuilder == null) {
111 setterBuilder = current;
112 } else {
113 return new AmbiguousBuilder(name, builder, charOffset, fileUri);
114 }
115 current = current.next;
116 }
117 assert(getterBuilder != null);
118 assert(setterBuilder != null);
119 return setter ? setterBuilder : getterBuilder;
120 } 135 }
121 136
122 bool hasLocalLabel(String name) => labels != null && labels.containsKey(name); 137 bool hasLocalLabel(String name) => labels != null && labels.containsKey(name);
123 138
124 void declareLabel(String name, Builder target) { 139 void declareLabel(String name, Builder target) {
125 if (isModifiable) { 140 if (isModifiable) {
126 labels ??= <String, Builder>{}; 141 labels ??= <String, Builder>{};
127 labels[name] = target; 142 labels[name] = target;
128 } else { 143 } else {
129 internalError("Can't extend an unmodifiable scope."); 144 internalError("Can't extend an unmodifiable scope.");
(...skipping 24 matching lines...) Expand all
154 169
155 // TODO(ahe): Rename to extend or something. 170 // TODO(ahe): Rename to extend or something.
156 void operator []=(String name, Builder member) { 171 void operator []=(String name, Builder member) {
157 if (isModifiable) { 172 if (isModifiable) {
158 local[name] = member; 173 local[name] = member;
159 } else { 174 } else {
160 internalError("Can't extend an unmodifiable scope."); 175 internalError("Can't extend an unmodifiable scope.");
161 } 176 }
162 } 177 }
163 178
179 void merge(Scope scope,
180 buildAmbiguousBuilder(String name, Builder existing, Builder member)) {
181 Map<String, Builder> map = local;
182
183 void mergeMember(String name, Builder member) {
184 Builder existing = map[name];
185 if (existing != null) {
186 if (existing != member) {
187 member = buildAmbiguousBuilder(name, existing, member);
188 }
189 }
190 map[name] = member;
191 }
192
193 scope.local.forEach(mergeMember);
194 map = setters;
195 scope.setters.forEach(mergeMember);
196 }
197
164 void forEach(f(String name, Builder member)) { 198 void forEach(f(String name, Builder member)) {
165 local.forEach(f); 199 local.forEach(f);
200 setters.forEach(f);
166 } 201 }
167 202
168 String get debugString { 203 String get debugString {
169 StringBuffer buffer = new StringBuffer(); 204 StringBuffer buffer = new StringBuffer();
170 int nestingLevel = writeOn(buffer); 205 int nestingLevel = writeOn(buffer);
171 for (int i = nestingLevel; i >= 0; i--) { 206 for (int i = nestingLevel; i >= 0; i--) {
172 buffer.writeln("${' ' * i}}"); 207 buffer.writeln("${' ' * i}}");
173 } 208 }
174 return "$buffer"; 209 return "$buffer";
175 } 210 }
176 211
177 int writeOn(StringSink sink) { 212 int writeOn(StringSink sink) {
178 int nestingLevel = (parent?.writeOn(sink) ?? -1) + 1; 213 int nestingLevel = (parent?.writeOn(sink) ?? -1) + 1;
179 String indent = " " * nestingLevel; 214 String indent = " " * nestingLevel;
180 sink.writeln("$indent{"); 215 sink.writeln("$indent{");
181 local.forEach((String name, Builder member) { 216 local.forEach((String name, Builder member) {
182 sink.writeln("$indent $name"); 217 sink.writeln("$indent $name");
183 }); 218 });
184 setters.forEach((String name, Builder member) { 219 setters.forEach((String name, Builder member) {
185 sink.writeln("$indent $name="); 220 sink.writeln("$indent $name=");
186 }); 221 });
187 return nestingLevel; 222 return nestingLevel;
188 } 223 }
189 } 224 }
190 225
226 class ScopeBuilder {
227 final Scope scope;
228
229 ScopeBuilder(this.scope);
230
231 void addMember(String name, Builder builder) {
232 scope.local[name] = builder;
233 }
234
235 void addSetter(String name, Builder builder) {
236 scope.setters[name] = builder;
237 }
238
239 Builder operator [](String name) => scope.local[name];
240 }
241
191 abstract class ProblemBuilder extends Builder { 242 abstract class ProblemBuilder extends Builder {
192 final String name; 243 final String name;
193 244
194 final Builder builder; 245 final Builder builder;
195 246
196 ProblemBuilder(this.name, this.builder, int charOffset, Uri fileUri) 247 ProblemBuilder(this.name, this.builder, int charOffset, Uri fileUri)
197 : super(null, charOffset, fileUri); 248 : super(null, charOffset, fileUri);
198 249
199 get target => null; 250 get target => null;
200 251
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
236 287
237 String get message => "Access error: '$name'."; 288 String get message => "Access error: '$name'.";
238 } 289 }
239 290
240 class AmbiguousBuilder extends ProblemBuilder { 291 class AmbiguousBuilder extends ProblemBuilder {
241 AmbiguousBuilder(String name, Builder builder, int charOffset, Uri fileUri) 292 AmbiguousBuilder(String name, Builder builder, int charOffset, Uri fileUri)
242 : super(name, builder, charOffset, fileUri); 293 : super(name, builder, charOffset, fileUri);
243 294
244 String get message => "Duplicated named: '$name'."; 295 String get message => "Duplicated named: '$name'.";
245 } 296 }
OLDNEW
« no previous file with comments | « pkg/front_end/lib/src/fasta/kernel/kernel_target.dart ('k') | pkg/front_end/lib/src/fasta/source/diet_listener.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698