Skip to content

Commit 5abe5a3

Browse files
josh11bjonmeow
andauthored
Stop allowing impl redeclarations to differ syntactically in where clause (#4850)
Based on [the lastest thinking on #4672](#4672 (comment)) , require a full syntactic match for impl redeclaration, instead of excluding the `where` restriction. This means no updates to the impl witness on redeclaration, and no diagnostics that those updates are consistent. Not included in this PR, but will need to be done in the future: * Support for assigning values to associated constants in the body of the impl definition. This will require moving the checking that non-function associated constants are set from the definition start to definition end. * Identify semantic redeclarations that are not syntactic matches to give a failed redeclaration diagnostic. This should be done once we are already identifying impl declarations with the same type structure in order to require they be identified in an impl_priority/match_first block. * Merging of the functions in `check/impl.cpp` that are now always called together. Also add some test coverage of `where` parsing I developed in PR I've now abandoned because of this new simplification of the impl redeclaration semantics. --------- Co-authored-by: Josh L <[email protected]> Co-authored-by: Jon Ross-Perkins <[email protected]>
1 parent 0d0e202 commit 5abe5a3

File tree

8 files changed

+393
-339
lines changed

8 files changed

+393
-339
lines changed

toolchain/check/handle_impl.cpp

Lines changed: 4 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -214,40 +214,11 @@ static auto PopImplIntroducerAndParamsAsNameComponent(
214214

215215
Parse::NodeId first_param_node_id =
216216
context.node_stack().PopForSoloNodeId<Parse::NodeKind::ImplIntroducer>();
217-
218217
// Subtracting 1 since we don't want to include the final `{` or `;` of the
219218
// declaration when performing syntactic match.
220-
auto end_node_kind = context.parse_tree().node_kind(end_of_decl_node_id);
221-
CARBON_CHECK(end_node_kind == Parse::NodeKind::ImplDefinitionStart ||
222-
end_node_kind == Parse::NodeKind::ImplDecl);
223219
Parse::Tree::PostorderIterator last_param_iter(end_of_decl_node_id);
224220
--last_param_iter;
225221

226-
// Following proposal #3763, exclude a final `where` clause, if present. See:
227-
// https://github.com/carbon-language/carbon-lang/blob/trunk/proposals/p3763.md#redeclarations
228-
229-
// Caches the NodeKind for the current value of *last_param_iter so
230-
if (context.parse_tree().node_kind(*last_param_iter) ==
231-
Parse::NodeKind::WhereExpr) {
232-
int where_operands_to_skip = 1;
233-
--last_param_iter;
234-
CARBON_CHECK(Parse::Tree::PostorderIterator(first_param_node_id) <
235-
last_param_iter);
236-
do {
237-
auto node_kind = context.parse_tree().node_kind(*last_param_iter);
238-
if (node_kind == Parse::NodeKind::WhereExpr) {
239-
// If we have a nested `where`, we need to see another `WhereOperand`
240-
// before we find the one that matches our original `WhereExpr` node.
241-
++where_operands_to_skip;
242-
} else if (node_kind == Parse::NodeKind::WhereOperand) {
243-
--where_operands_to_skip;
244-
}
245-
--last_param_iter;
246-
CARBON_CHECK(Parse::Tree::PostorderIterator(first_param_node_id) <
247-
last_param_iter);
248-
} while (where_operands_to_skip > 0);
249-
}
250-
251222
return {
252223
.name_loc_id = Parse::NodeId::None,
253224
.name_id = SemIR::NameId::None,
@@ -315,9 +286,6 @@ static auto IsValidImplRedecl(Context& context, SemIR::Impl& new_impl,
315286

316287
// TODO: Only allow redeclaration in a match_first/impl_priority block.
317288

318-
// TODO: Merge information from the new declaration into the old one as
319-
// needed.
320-
321289
return true;
322290
}
323291

@@ -375,6 +343,8 @@ static auto BuildImplDecl(Context& context, Parse::AnyImplDeclId node_id,
375343
// Add the impl declaration.
376344
bool invalid_redeclaration = false;
377345
auto lookup_bucket_ref = context.impls().GetOrAddLookupBucket(impl_info);
346+
// TODO: Detect two impl declarations with the same self type and interface,
347+
// and issue an error if they don't match.
378348
for (auto prev_impl_id : lookup_bucket_ref) {
379349
if (MergeImplRedecl(context, impl_info, prev_impl_id)) {
380350
if (IsValidImplRedecl(context, impl_info, prev_impl_id)) {
@@ -392,15 +362,13 @@ static auto BuildImplDecl(Context& context, Parse::AnyImplDeclId node_id,
392362
if (!impl_decl.impl_id.has_value()) {
393363
impl_info.generic_id = BuildGeneric(context, impl_decl_id);
394364
impl_info.witness_id = ImplWitnessForDeclaration(context, impl_info);
395-
AddConstantsToImplWitnessFromConstraint(
396-
context, impl_info, impl_info.witness_id, impl_decl.impl_id);
365+
AddConstantsToImplWitnessFromConstraint(context, impl_info,
366+
impl_info.witness_id);
397367
FinishGenericDecl(context, impl_decl_id, impl_info.generic_id);
398368
impl_decl.impl_id = context.impls().Add(impl_info);
399369
lookup_bucket_ref.push_back(impl_decl.impl_id);
400370
} else {
401371
const auto& first_impl = context.impls().Get(impl_decl.impl_id);
402-
AddConstantsToImplWitnessFromConstraint(
403-
context, impl_info, first_impl.witness_id, impl_decl.impl_id);
404372
FinishGenericRedecl(context, impl_decl_id, first_impl.generic_id);
405373
}
406374

toolchain/check/impl.cpp

Lines changed: 9 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,6 @@ static auto NoteAssociatedFunction(Context& context,
3232
function.name_id);
3333
}
3434

35-
// Adds the location of the previous declaration to a diagnostic.
36-
static auto NotePreviousDecl(Context& context,
37-
Context::DiagnosticBuilder& builder,
38-
SemIR::ImplId impl_id) -> void {
39-
CARBON_DIAGNOSTIC(ImplPreviousDeclHere, Note,
40-
"impl previously declared here");
41-
const auto& impl = context.impls().Get(impl_id);
42-
builder.Note(impl.latest_decl_id(), ImplPreviousDeclHere);
43-
}
44-
4535
// Checks that `impl_function_id` is a valid implementation of the function
4636
// described in the interface as `interface_function_id`. Returns the value to
4737
// put into the corresponding slot in the witness table, which can be
@@ -88,6 +78,7 @@ static auto CheckAssociatedFunctionImplementation(
8878
}
8979

9080
// Builds an initial empty witness.
81+
// TODO: Fill the witness with the rewrites from the declaration.
9182
auto ImplWitnessForDeclaration(Context& context, const SemIR::Impl& impl)
9283
-> SemIR::InstId {
9384
CARBON_CHECK(!impl.has_definition_started());
@@ -159,11 +150,10 @@ static auto WitnessAccessMatchesInterface(
159150
return false;
160151
}
161152

153+
// TODO: Merge this function into `ImplWitnessForDeclaration`.
162154
auto AddConstantsToImplWitnessFromConstraint(Context& context,
163155
const SemIR::Impl& impl,
164-
SemIR::InstId witness_id,
165-
SemIR::ImplId prev_decl_id)
166-
-> void {
156+
SemIR::InstId witness_id) -> void {
167157
CARBON_CHECK(!impl.has_definition_started());
168158
CARBON_CHECK(witness_id.has_value());
169159
if (witness_id == SemIR::ErrorInst::SingletonInstId) {
@@ -229,16 +219,13 @@ auto AddConstantsToImplWitnessFromConstraint(Context& context,
229219
}
230220
}
231221

232-
// For each non-function associated constant, update witness entry.
222+
// For each non-function associated constant, set the witness entry.
233223
for (auto index : llvm::seq(assoc_entities.size())) {
234224
auto decl_id =
235225
context.constant_values().GetConstantInstId(assoc_entities[index]);
236226
CARBON_CHECK(decl_id.has_value(), "Non-constant associated entity");
237227
if (auto decl =
238228
context.insts().TryGetAs<SemIR::AssociatedConstantDecl>(decl_id)) {
239-
const auto& assoc_const =
240-
context.associated_constants().Get(decl->assoc_const_id);
241-
auto& witness_value = witness_block[index];
242229
auto rewrite_value = rewrite_values[index];
243230

244231
// If the associated constant has a symbolic type, convert the rewrite
@@ -264,6 +251,8 @@ auto AddConstantsToImplWitnessFromConstraint(Context& context,
264251
// value was constant.
265252
if (!rewrite_value.is_constant() &&
266253
rewrite_value != SemIR::ErrorInst::SingletonConstantId) {
254+
const auto& assoc_const =
255+
context.associated_constants().Get(decl->assoc_const_id);
267256
CARBON_DIAGNOSTIC(
268257
AssociatedConstantNotConstantAfterConversion, Error,
269258
"associated constant {0} given value that is not constant "
@@ -276,39 +265,9 @@ auto AddConstantsToImplWitnessFromConstraint(Context& context,
276265
}
277266
}
278267

279-
if (witness_value.has_value() &&
280-
witness_value != SemIR::ErrorInst::SingletonInstId) {
281-
// TODO: Support just using the witness values if the redeclaration uses
282-
// `where _`, per proposal #1084.
283-
if (!rewrite_value.has_value()) {
284-
CARBON_DIAGNOSTIC(AssociatedConstantMissingInRedecl, Error,
285-
"associated constant {0} given value in "
286-
"declaration but not redeclaration",
287-
SemIR::NameId);
288-
auto builder = context.emitter().Build(
289-
impl.latest_decl_id(), AssociatedConstantMissingInRedecl,
290-
assoc_const.name_id);
291-
NotePreviousDecl(context, builder, prev_decl_id);
292-
builder.Emit();
293-
continue;
294-
}
295-
auto witness_const_id = context.constant_values().Get(witness_value);
296-
if (witness_const_id != rewrite_value &&
297-
rewrite_value != SemIR::ErrorInst::SingletonConstantId) {
298-
// TODO: Figure out how to print the two different values
299-
CARBON_DIAGNOSTIC(
300-
AssociatedConstantDifferentInRedecl, Error,
301-
"redeclaration with different value for associated constant {0}",
302-
SemIR::NameId);
303-
auto builder = context.emitter().Build(
304-
impl.latest_decl_id(), AssociatedConstantDifferentInRedecl,
305-
assoc_const.name_id);
306-
NotePreviousDecl(context, builder, prev_decl_id);
307-
builder.Emit();
308-
continue;
309-
}
310-
} else if (rewrite_value.has_value()) {
311-
witness_value = context.constant_values().GetInstId(rewrite_value);
268+
if (rewrite_value.has_value()) {
269+
witness_block[index] =
270+
context.constant_values().GetInstId(rewrite_value);
312271
}
313272
}
314273
}

toolchain/check/impl.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,7 @@ auto ImplWitnessForDeclaration(Context& context, const SemIR::Impl& impl)
1616

1717
auto AddConstantsToImplWitnessFromConstraint(Context& context,
1818
const SemIR::Impl& impl,
19-
SemIR::InstId witness_id,
20-
SemIR::ImplId prev_decl_id)
21-
-> void;
19+
SemIR::InstId witness_id) -> void;
2220

2321
// Update `impl`'s witness at the start of a definition.
2422
auto ImplWitnessStartDefinition(Context& context, SemIR::Impl& impl) -> void;

0 commit comments

Comments
 (0)