mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 13:11:05 +01:00
Redeclaration support for impl declarations. (#3717)
Maintain a mapping from (self type, constraint) to `ImplId` on the `Impl` value store so that we can perform redeclaration lookup.
This commit is contained in:
@@ -365,7 +365,7 @@ class Context {
|
||||
auto interfaces() -> ValueStore<SemIR::InterfaceId>& {
|
||||
return sem_ir().interfaces();
|
||||
}
|
||||
auto impls() -> ValueStore<SemIR::ImplId>& { return sem_ir().impls(); }
|
||||
auto impls() -> SemIR::ImplStore& { return sem_ir().impls(); }
|
||||
auto import_irs() -> ValueStore<SemIR::ImportIRId>& {
|
||||
return sem_ir().import_irs();
|
||||
}
|
||||
|
||||
@@ -153,21 +153,17 @@ static auto BuildImplDecl(Context& context, Parse::AnyImplDeclId parse_node)
|
||||
auto name_context = context.decl_name_stack().FinishImplName();
|
||||
CARBON_CHECK(name_context.state == DeclNameStack::NameContext::State::Empty);
|
||||
|
||||
// Add the impl declaration.
|
||||
auto impl_decl = SemIR::ImplDecl{SemIR::ImplId::Invalid, decl_block_id};
|
||||
auto impl_decl_id = context.AddPlaceholderInst({parse_node, impl_decl});
|
||||
// TODO: Check for an orphan `impl`.
|
||||
|
||||
// TODO: Check whether this is a redeclaration.
|
||||
// TODO: Check parameters. Store them on the `Impl` in some form.
|
||||
static_cast<void>(params_id);
|
||||
|
||||
// Create a new impl if this isn't a valid redeclaration.
|
||||
if (!impl_decl.impl_id.is_valid()) {
|
||||
impl_decl.impl_id = context.impls().Add(
|
||||
{.self_id = self_type_id, .constraint_id = constraint_type_id});
|
||||
}
|
||||
|
||||
// Write the impl ID into the ImplDecl.
|
||||
context.ReplaceInstBeforeConstantUse(impl_decl_id, {parse_node, impl_decl});
|
||||
// Add the impl declaration.
|
||||
// TODO: Does lookup in an impl file need to look for a prior impl declaration
|
||||
// in the api file?
|
||||
auto impl_id = context.impls().LookupOrAdd(self_type_id, constraint_type_id);
|
||||
auto impl_decl = SemIR::ImplDecl{impl_id, decl_block_id};
|
||||
auto impl_decl_id = context.AddInst({parse_node, impl_decl});
|
||||
|
||||
// For an `extend impl` declaration, mark the impl as extending this `impl`.
|
||||
if (!!(context.decl_state_stack().innermost().modifier_set &
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
||||
// Exceptions. See /LICENSE for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
// AUTOUPDATE
|
||||
|
||||
interface I {}
|
||||
|
||||
impl i32 as I {}
|
||||
|
||||
// CHECK:STDERR: fail_redefinition.carbon:[[@LINE+6]]:1: ERROR: Redefinition of `impl i32 as I`.
|
||||
// CHECK:STDERR: impl i32 as I {}
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR: fail_redefinition.carbon:[[@LINE-5]]:1: Previous definition was here.
|
||||
// CHECK:STDERR: impl i32 as I {}
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~
|
||||
impl i32 as I {}
|
||||
|
||||
// CHECK:STDOUT: --- fail_redefinition.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %.1: type = interface_type @I [template]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace {.I = %I.decl} [template]
|
||||
// CHECK:STDOUT: %I.decl = interface_decl @I, ()
|
||||
// CHECK:STDOUT: impl_decl @impl, (<unexpected instref inst+3>)
|
||||
// CHECK:STDOUT: impl_decl @impl, (<unexpected instref inst+5>)
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: interface @I {
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: impl @impl: i32 as I {
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
+16
-9
@@ -6,22 +6,28 @@
|
||||
|
||||
interface I {}
|
||||
|
||||
impl i32 as I;
|
||||
|
||||
class X {
|
||||
impl i32 as I;
|
||||
}
|
||||
|
||||
impl i32 as I {}
|
||||
|
||||
// TODO: Reject this redefinition.
|
||||
impl i32 as I {}
|
||||
|
||||
// CHECK:STDOUT: --- todo_redefinition.carbon
|
||||
// CHECK:STDOUT: --- redeclaration.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %.1: type = interface_type @I [template]
|
||||
// CHECK:STDOUT: %X: type = class_type @X [template]
|
||||
// CHECK:STDOUT: %.2: type = struct_type {} [template]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace {.I = %I.decl} [template]
|
||||
// CHECK:STDOUT: package: <namespace> = namespace {.I = %I.decl, .X = %X.decl} [template]
|
||||
// CHECK:STDOUT: %I.decl = interface_decl @I, ()
|
||||
// CHECK:STDOUT: impl_decl @impl.1, (<unexpected instref inst+3>)
|
||||
// CHECK:STDOUT: impl_decl @impl.2, (<unexpected instref inst+5>)
|
||||
// CHECK:STDOUT: impl_decl @impl, (<unexpected instref inst+3>)
|
||||
// CHECK:STDOUT: %X.decl = class_decl @X, ()
|
||||
// CHECK:STDOUT: impl_decl @impl, (<unexpected instref inst+10>)
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: interface @I {
|
||||
@@ -29,12 +35,13 @@ impl i32 as I {}
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: impl @impl.1: i32 as I {
|
||||
// CHECK:STDOUT: impl @impl: i32 as I {
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: impl @impl.2: i32 as I {
|
||||
// CHECK:STDOUT: class @X {
|
||||
// CHECK:STDOUT: impl_decl @impl, (<unexpected instref inst+7>)
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: }
|
||||
@@ -69,6 +69,7 @@ cc_library(
|
||||
],
|
||||
hdrs = [
|
||||
"file.h",
|
||||
"impl.h",
|
||||
"value_stores.h",
|
||||
],
|
||||
deps = [
|
||||
|
||||
+4
-36
@@ -13,6 +13,7 @@
|
||||
#include "toolchain/base/value_store.h"
|
||||
#include "toolchain/base/yaml.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
#include "toolchain/sem_ir/impl.h"
|
||||
#include "toolchain/sem_ir/type_info.h"
|
||||
#include "toolchain/sem_ir/value_stores.h"
|
||||
|
||||
@@ -175,39 +176,6 @@ struct Interface : public Printable<Interface> {
|
||||
bool defined = false;
|
||||
};
|
||||
|
||||
// An implementation of a constraint.
|
||||
struct Impl : public Printable<Impl> {
|
||||
auto Print(llvm::raw_ostream& out) const -> void {
|
||||
out << "{self: " << self_id << ", constraint: " << constraint_id << "}";
|
||||
}
|
||||
|
||||
// Determines whether this impl has been fully defined. This is false until we
|
||||
// reach the `}` of the impl definition.
|
||||
auto is_defined() const -> bool { return defined; }
|
||||
|
||||
// The following members always have values, and do not change throughout the
|
||||
// lifetime of the interface.
|
||||
|
||||
// TODO: Track the generic parameters for `impl forall`.
|
||||
// The type for which the impl is implementing a constraint.
|
||||
TypeId self_id;
|
||||
// The constraint that the impl implements.
|
||||
TypeId constraint_id;
|
||||
|
||||
// The following members are set at the `{` of the impl definition.
|
||||
|
||||
// The definition of the impl. This is an ImplDecl.
|
||||
InstId definition_id = InstId::Invalid;
|
||||
// The impl scope.
|
||||
NameScopeId scope_id = NameScopeId::Invalid;
|
||||
// The first block of the impl body.
|
||||
// TODO: Handle control flow in the impl body, such as if-expressions.
|
||||
InstBlockId body_block_id = InstBlockId::Invalid;
|
||||
|
||||
// The following members are set at the `}` of the impl definition.
|
||||
bool defined = false;
|
||||
};
|
||||
|
||||
// Provides semantic analysis on a Parse::Tree.
|
||||
class File : public Printable<File> {
|
||||
public:
|
||||
@@ -302,8 +270,8 @@ class File : public Printable<File> {
|
||||
auto interfaces() const -> const ValueStore<InterfaceId>& {
|
||||
return interfaces_;
|
||||
}
|
||||
auto impls() -> ValueStore<ImplId>& { return impls_; }
|
||||
auto impls() const -> const ValueStore<ImplId>& { return impls_; }
|
||||
auto impls() -> ImplStore& { return impls_; }
|
||||
auto impls() const -> const ImplStore& { return impls_; }
|
||||
auto import_irs() -> ValueStore<ImportIRId>& { return import_irs_; }
|
||||
auto import_irs() const -> const ValueStore<ImportIRId>& {
|
||||
return import_irs_;
|
||||
@@ -378,7 +346,7 @@ class File : public Printable<File> {
|
||||
ValueStore<InterfaceId> interfaces_;
|
||||
|
||||
// Storage for impls.
|
||||
ValueStore<ImplId> impls_;
|
||||
ImplStore impls_;
|
||||
|
||||
// Related IRs. There will always be at least one entry, the builtin IR (used
|
||||
// for references of builtins).
|
||||
|
||||
@@ -487,5 +487,8 @@ struct llvm::DenseMapInfo<Carbon::SemIR::InstId>
|
||||
template <>
|
||||
struct llvm::DenseMapInfo<Carbon::SemIR::NameScopeId>
|
||||
: public Carbon::IndexMapInfo<Carbon::SemIR::NameScopeId> {};
|
||||
template <>
|
||||
struct llvm::DenseMapInfo<Carbon::SemIR::TypeId>
|
||||
: public Carbon::IndexMapInfo<Carbon::SemIR::TypeId> {};
|
||||
|
||||
#endif // CARBON_TOOLCHAIN_SEM_IR_IDS_H_
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
||||
// Exceptions. See /LICENSE for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#ifndef CARBON_TOOLCHAIN_SEM_IR_IMPL_H_
|
||||
#define CARBON_TOOLCHAIN_SEM_IR_IMPL_H_
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
|
||||
namespace Carbon::SemIR {
|
||||
|
||||
// An implementation of a constraint.
|
||||
struct Impl : public Printable<Impl> {
|
||||
auto Print(llvm::raw_ostream& out) const -> void {
|
||||
out << "{self: " << self_id << ", constraint: " << constraint_id << "}";
|
||||
}
|
||||
|
||||
// Determines whether this impl has been fully defined. This is false until we
|
||||
// reach the `}` of the impl definition.
|
||||
auto is_defined() const -> bool { return defined; }
|
||||
|
||||
// The following members always have values, and do not change throughout the
|
||||
// lifetime of the interface.
|
||||
|
||||
// TODO: Track the generic parameters for `impl forall`.
|
||||
// The type for which the impl is implementing a constraint.
|
||||
TypeId self_id;
|
||||
// The constraint that the impl implements.
|
||||
TypeId constraint_id;
|
||||
|
||||
// The following members are set at the `{` of the impl definition.
|
||||
|
||||
// The definition of the impl. This is an ImplDecl.
|
||||
InstId definition_id = InstId::Invalid;
|
||||
// The impl scope.
|
||||
NameScopeId scope_id = NameScopeId::Invalid;
|
||||
// The first block of the impl body.
|
||||
// TODO: Handle control flow in the impl body, such as if-expressions.
|
||||
InstBlockId body_block_id = InstBlockId::Invalid;
|
||||
|
||||
// The following members are set at the `}` of the impl definition.
|
||||
bool defined = false;
|
||||
};
|
||||
|
||||
// A collection of `Impl`s, which can be accessed by the self type and
|
||||
// constraint implemented.
|
||||
class ImplStore {
|
||||
public:
|
||||
// Looks up the impl with this self type and constraint, or creates a new
|
||||
// `Impl` if none exists.
|
||||
// TODO: Handle parameters.
|
||||
auto LookupOrAdd(TypeId self_id, TypeId constraint_id) -> ImplId {
|
||||
auto [it, added] =
|
||||
lookup_.insert({{self_id, constraint_id}, ImplId::Invalid});
|
||||
if (added) {
|
||||
it->second =
|
||||
values_.Add({.self_id = self_id, .constraint_id = constraint_id});
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// Returns a mutable value for an ID.
|
||||
auto Get(ImplId id) -> Impl& { return values_.Get(id); }
|
||||
|
||||
// Returns the value for an ID.
|
||||
auto Get(ImplId id) const -> const Impl& { return values_.Get(id); }
|
||||
|
||||
auto OutputYaml() const -> Yaml::OutputMapping {
|
||||
return values_.OutputYaml();
|
||||
}
|
||||
|
||||
auto array_ref() const -> llvm::ArrayRef<Impl> { return values_.array_ref(); }
|
||||
auto size() const -> size_t { return values_.size(); }
|
||||
|
||||
private:
|
||||
ValueStore<ImplId> values_;
|
||||
llvm::DenseMap<std::pair<TypeId, TypeId>, ImplId> lookup_;
|
||||
};
|
||||
|
||||
} // namespace Carbon::SemIR
|
||||
|
||||
#endif // CARBON_TOOLCHAIN_SEM_IR_IMPL_H_
|
||||
Reference in New Issue
Block a user