Repository: carbon-language/carbon-lang
File: toolchain/check/decl_name_stack.h (C/C++)

Code before:
  // containing it.
  auto PeekParentScopeId() const -> SemIR::NameScopeId {
    return decl_name_stack_.back().parent_scope_id;
  }

  // Peeks the resolution scope index of the name on top of the stack.
  auto PeekInitialScopeIndex() const -> ScopeIndex {
    return decl_name_stack_.back().initial_scope_index;
  }

  // Temporarily remove the current declaration name and its associated scopes
  // from the stack. Can only be called once the name is finished.
  auto Suspend() -> SuspendedName;

  // Restore a previously suspended name.
  auto Restore(SuspendedName sus) -> void;

  // Adds a name to name lookup. Assumes duplicates are already handled.
  auto AddName(NameContext name_context, SemIR::InstId target_id,
               SemIR::AccessKind access_kind) -> void;

  // Adds a name to name lookup. Prints a diagnostic for name conflicts.
  auto AddNameOrDiagnose(NameContext name_context, SemIR::InstId target_id,
                         SemIR::AccessKind access_kind) -> void;

  // Adds a name to name lookup if not already declared or poisoned in this
  // scope. If declared, returns the existing instruction and false. If
  // poisoned, returns invalid instruction and true.
  // TODO: Return the poisoning instruction if poisoned.
  // name has already been declared in this scope.
  auto LookupOrAddName(NameContext name_context, SemIR::InstId target_id,
                       SemIR::AccessKind access_kind)
      -> std::pair<SemIR::InstId, bool>;

 private:
  // Returns a name context corresponding to an empty name.
  auto MakeEmptyNameContext() -> NameContext;

  // Appends a name to the given name context, and performs a lookup to find
  // what, if anything, the name refers to.
  auto ApplyAndLookupName(NameContext& name_context, SemIR::LocId loc_id,
                          SemIR::NameId name_id) -> void;

  // Attempts to resolve the given name context as a scope, and returns the
  // corresponding scope. Issues a suitable diagnostic and returns Invalid if
  // the name doesn't resolve to a scope.
  auto ResolveAsScope(const NameContext& name_context,
                      const NameComponent& name) const
      -> std::pair<SemIR::NameScopeId, SemIR::SpecificId>;

  // The linked context.

Review comment (bug):
This phrasing makes it hard to tell whether "not" applies to "poisoned". I think this doesn't overwrite poisoned entries, so how about using "neither ... nor" to emphasize:

```suggestion
  // Adds a name to name lookup if neither already declared nor poisoned in this
```

If I'm wrong, swapping ordering could help:

```suggestion
  // Adds a name to name lookup if poisoned or not already declared in this
```

Or, "either" can also help make it clear "not" wouldn't apply to "poisoned":

```suggestion
  // Adds a name to name lookup if either not already declared or poisoned in this
```


Code after:
  // containing it.
  auto PeekParentScopeId() const -> SemIR::NameScopeId {
    return decl_name_stack_.back().parent_scope_id;
  }

  // Peeks the resolution scope index of the name on top of the stack.
  auto PeekInitialScopeIndex() const -> ScopeIndex {
    return decl_name_stack_.back().initial_scope_index;
  }

  // Temporarily remove the current declaration name and its associated scopes
  // from the stack. Can only be called once the name is finished.
  auto Suspend() -> SuspendedName;

  // Restore a previously suspended name.
  auto Restore(SuspendedName sus) -> void;

  // Adds a name to name lookup. Assumes duplicates are already handled.
  auto AddName(NameContext name_context, SemIR::InstId target_id,
               SemIR::AccessKind access_kind) -> void;

  // Adds a name to name lookup. Prints a diagnostic for name conflicts.
  auto AddNameOrDiagnose(NameContext name_context, SemIR::InstId target_id,
                         SemIR::AccessKind access_kind) -> void;

  // Adds a name to name lookup if neither already declared nor poisoned in this
  // scope. If declared, returns the existing instruction and false. If
  // poisoned, returns an invalid instruction and true.
  // TODO: Return the poisoning instruction if poisoned.
  auto LookupOrAddName(NameContext name_context, SemIR::InstId target_id,
                       SemIR::AccessKind access_kind)
      -> std::pair<SemIR::InstId, bool>;

 private:
  // Returns a name context corresponding to an empty name.
  auto MakeEmptyNameContext() -> NameContext;

  // Appends a name to the given name context, and performs a lookup to find
  // what, if anything, the name refers to.
  auto ApplyAndLookupName(NameContext& name_context, SemIR::LocId loc_id,
                          SemIR::NameId name_id) -> void;

  // Attempts to resolve the given name context as a scope, and returns the
  // corresponding scope. Issues a suitable diagnostic and returns Invalid if
  // the name doesn't resolve to a scope.
  auto ResolveAsScope(const NameContext& name_context,
                      const NameComponent& name) const
      -> std::pair<SemIR::NameScopeId, SemIR::SpecificId>;

  // The linked context.
  Context* context_;