Skip to content

feat: Type aliases and associated types - #79

Open
septechx wants to merge 86 commits into
oxilang:devfrom
septechx:feat-type-item
Open

septechx wants to merge 86 commits into
oxilang:devfrom
septechx:feat-type-item

Conversation

@septechx

@septechx septechx commented Jul 21, 2026 •

Copy link
Copy Markdown
Member
  • feat: Start work on implementing type aliases
  • feat: Type alias lowering to HIR
  • feat: Type alias type checking and lowering to THIR
  • feat: Associated type parsing
  • feat: New path resolution to allow for resolving in Self or generics

Summary by CodeRabbit

  • New Features

    • Added top-level and associated type declarations, generic aliases, and trait-qualified associated-type projections.
    • Improved support for generic defaults, aliases in type annotations and method calls, and trait implementations.
  • Bug Fixes

    • Improved detection of recursive, ambiguous, unresolved, and invalid types, with clearer parser and type-checking diagnostics.
  • Breaking Changes

    • Removed built-in code generation, linking, and related output options.
  • Documentation

    • Updated branding, project status messaging, and introductory examples.
  • Tests

    • Expanded coverage for aliases, projections, associated types, generics, and error cases.

@coderabbitai

coderabbitai Bot commented Jul 21, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: Repository: oxilang/oxi/.coderabbit.yaml
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: a4af080f-847e-463d-81b1-1f96d4f9105e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: oxilang/oxi/.coderabbit.yaml
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: c05b66f1-f4b5-4da4-8da6-fcda8e633396
📥 Commits

Reviewing files that changed from the base of the PR and between e4327ae and 6194da3.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (36)
  • Cargo.toml
  • build.rs
  • include/llvm_bindings.cpp
  • src/ast/mod.rs
  • src/backend/diagnostics.toml
  • src/backend/linker/gcc.rs
  • src/backend/linker/ld.rs
  • src/backend/linker/mod.rs
  • src/backend/mod.rs
  • src/bindings/llvm_bindings.rs
  • src/bindings/mod.rs
  • src/cli.rs
  • src/codegen/arch.rs
  • src/codegen/builtin/asm.rs
  • src/codegen/builtin/import/header.rs
  • src/codegen/builtin/import/mod.rs
  • src/codegen/builtin/import/resolve_lib.rs
  • src/codegen/builtin/mod.rs
  • src/codegen/builtin/slice.rs
  • src/codegen/compile_expr.rs
  • src/codegen/compile_type.rs
  • src/codegen/compiler.rs
  • src/codegen/emmiter.rs
  • src/codegen/inkwell_ext.rs
  • src/codegen/mod.rs
  • src/codegen/pointer.rs
  • src/codegen/runtime.rs
  • src/main.rs
  • src/parser/stmt.rs
  • src/typeck/diagnostics.toml
  • src/typeck/passes/check/mod.rs
  • src/typeck/passes/collect.rs
  • src/typeck/types.rs
  • tests/integration/traits/proj_self_trait_args_mismatch.oxi
  • tests/integration/type_alias/invalid_type_path_fn.oxi
  • tests/integration/type_alias/static_call_via_alias.oxi
💤 Files with no reviewable changes (27)
  • src/bindings/mod.rs
  • src/codegen/emmiter.rs
  • src/codegen/arch.rs
  • src/backend/diagnostics.toml
  • Cargo.toml
  • src/codegen/builtin/import/resolve_lib.rs
  • src/codegen/builtin/mod.rs
  • src/codegen/runtime.rs
  • src/backend/linker/ld.rs
  • src/main.rs
  • src/codegen/compile_type.rs
  • src/codegen/builtin/slice.rs
  • src/backend/linker/gcc.rs
  • src/codegen/builtin/import/header.rs
  • src/codegen/compile_expr.rs
  • build.rs
  • src/codegen/builtin/asm.rs
  • src/codegen/mod.rs
  • include/llvm_bindings.cpp
  • src/codegen/builtin/import/mod.rs
  • src/backend/mod.rs
  • src/codegen/compiler.rs
  • src/codegen/inkwell_ext.rs
  • src/backend/linker/mod.rs
  • src/cli.rs
  • src/codegen/pointer.rs
  • src/bindings/llvm_bindings.rs

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

Type aliases, associated types, projection types, generic defaults, recursive-type checks, and related diagnostics now span parsing, AST validation, HIR lowering, resolution, type checking, THIR lowering, and integration tests. The backend and LLVM code-generation modules were also removed.

Changes

Type alias and projection compiler flow

Layer / File(s) Summary
Syntax and AST support
docs/grammar.txt, src/lexer/*, src/parser/*, src/ast/*
The grammar, lexer, parser, AST, visitors, validators, and diagnostics support type declarations, associated types, projection syntax, and generic-default validation.
HIR lowering and resolution
src/hir/*, src/resolve/*
Type aliases and associated types lower into HIR. Resolver definitions, type namespaces, module mappings, node IDs, and projection paths are updated.
Type representation and conversion
src/typeck/types.rs, src/typeck/fold.rs, src/typeck/visitor.rs, src/typeck/infctx.rs, src/typeck/unify.rs
The type checker adds projection types, fallible HIR conversion, alias expansion, generic-default handling, recursive folding, visitor traversal, and projection-aware unification.
Collection, body checking, and coherence
src/typeck/mod.rs, src/typeck/passes/*
Type collection, body checking, method calls, struct initialization, coherence, associated-type lookup, normalization, and recursive-alias detection use shared resolver and inference state.
Integration coverage and supporting updates
tests/integration/*, AGENTS.md, README.md, lib/oxi/*, crates/oxic_test/src/lib.rs
Integration tests cover aliases, associated types, projections, generic defaults, recursive definitions, invalid references, and method calls. Documentation, standard-library examples, and test path tracking are updated.
Backend removal
Cargo.toml, build.rs, src/backend/*, src/bindings/*, src/codegen/*, src/main.rs, src/cli.rs
LLVM bindings, code generation, linker support, runtime integration, related CLI options, and their build dependencies are removed.

Priority: ⬇️ Low

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Parser
  participant AST
  participant Resolver
  participant Typeck
  participant THIR
  Parser->>AST: Build type alias or projection node
  AST->>Resolver: Assign IDs and collect type definitions
  Resolver->>Typeck: Provide definitions, modules, and paths
  Typeck->>Typeck: Convert, normalize, and unify types
  Typeck->>THIR: Provide resolved node types
  THIR->>THIR: Lower resolved aliases and associated items
Loading

Merge Risk: ⚪ Minimal · up to 6194d

No actionable regression is established for the reviewed head. The compiler’s default command did not produce a program executable before this change, and the remaining comment concerns wording only.

Security Architecture Review

Security architecture risk: 🔵 Low · up to 6194d

The new language features include recursion and invalid-type checks. No introduced privilege escalation or broader security exposure was demonstrated, but visibility behavior and some combined failure paths remain uncertain.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The directly demonstrated input-controlled scope is compiler source affecting resolution and state within one compilation. A hosted-service, tenant or credential boundary is not established by the inspected flow.

Trust Boundaries and Controls

  • observed — Direct qualified-path lookup returns the selected binding without filtering its visibility at both base and head. That behavior predates this PR and is not, by itself, evidence of an introduced privacy bypass. The new associated-type policy still requires clarification.
  • observed — The body-side conversion path propagates conversion failures into diagnostics and Ty::Error. Projection normalization rejects repeated full identity keys and removes its active key after either successful or failed recursive resolution.

Resilience and Maintainability Implications

  • observed — Alias expansion tracks active definition identities and removes them after callbacks return, including Result errors. Associated-type default resolution similarly removes its active definition before propagating an error. These controls contain repeated expansion within the inspected transitions.

Hardening Proposals

  • proposed — Define whether visibility governs direct paths and associated-type projections, then apply that policy consistently. This is a contract-hardening proposal, not a verified authorization vulnerability.
  • proposed — Establish that mixed alias/projection cycles cannot produce Ty::Error without a recorded diagnostic before final output assertions. The inspected alias helper permits that return shape, but a reachable assertion failure was not established.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding type aliases and associated types.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

A rabbit reads each line,
The patch grows clear beneath the moon,
Small changes hop in place,
Tests guard the garden path,
Reviews bloom before the dawn.

Comment @coderabbitai help to get the list of available commands.

@septechx septechx added the enhancement New feature or request label Jul 21, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/resolve/late.rs (1)

206-251: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

defer_type_relative_path bails out on the first failed prefix candidate instead of trying shorter ones.

The "Case 2" loop (Lines 221-248) is designed to try progressively shorter module prefixes to find the module::...::Type boundary, but .ok()? (Line 228) and ? (Line 232) use Option-chaining semantics: any failure on the first (longest) candidate causes the entire function to return None, never reaching shorter prefixes later in the loop. Since the loop starts at segments.len() - 1 and shrinks, the longest candidate will almost always include the type segment inside the "module" prefix and fail to resolve as a module — meaning the correct (shorter) split is never tried for any 3+ segment type-relative path (e.g. a::b::Type::method).

🐛 Proposed fix
-            let module = self
-                .resolver
-                .resolve_module_path(self.resolver.module_idx, module_prefix)
-                .ok()?;
-
-            let resolution = self.resolver.modules[module]
-                .resolutions
-                .get(&type_seg.ident.value)?;
+            let Ok(module) = self
+                .resolver
+                .resolve_module_path(self.resolver.module_idx, module_prefix)
+            else {
+                continue;
+            };
+
+            let Some(resolution) = self.resolver.modules[module]
+                .resolutions
+                .get(&type_seg.ident.value)
+            else {
+                continue;
+            };

Also applies to: 221-248

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/resolve/late.rs` around lines 206 - 251, Update the Case 2 loop in
defer_type_relative_path to skip a prefix when resolve_module_path fails or when
the module resolution lacks the candidate type segment, rather than returning
None. Preserve the existing type-definition and trailing-segment checks,
allowing all progressively shorter prefixes to be tried before returning None.
src/parser/stmt.rs (1)

96-176: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Struct associated types can be declared without a body, unlike struct methods.

parse_struct_decl_item's Fn branch emits StructMethodMissingBody when a method has no body, but the new Type branch (Lines 147-151) never checks whether type_ is Some. Since structs are concrete (no later "impl" phase fills in a struct's own inline associated type, unlike trait declarations), a bodyless type Foo; inside a struct { ... } silently produces AssocItemKind::Type { type_: None } with no diagnostic, similar to how parse_impl_item guards this with ImplTypeMissingBody.

🐛 Proposed fix
             TokenKind::Type => {
                 let mut assoc = parse_type_assoc_item(parser)?;
+                let has_body = matches!(&assoc.kind, AssocItemKind::Type { type_: Some(_), .. });
+                if !has_body {
+                    builders::emit_at(
+                        parser.ctx,
+                        assoc.span,
+                        parser.current_token().module_id,
+                        diag::StructTypeMissingBody,
+                        diag_params! {},
+                    );
+                }
                 assoc.visibility = visibility;
                 items.push(assoc);
             }

Note: this requires adding a StructTypeMissingBody entry to src/parser/diagnostics.toml, which is not part of the files provided for this review.

Also applies to: 147-151

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/parser/stmt.rs` around lines 96 - 176, Update the TokenKind::Type branch
in parse_struct_decl_item to detect when the parsed associated type has no body
(type_ is None) and emit the new StructTypeMissingBody diagnostic at the
associated type name/span, while still adding the item. Add the corresponding
StructTypeMissingBody entry to parser diagnostics, following the existing
ImplTypeMissingBody and StructMethodMissingBody patterns.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/grammar.txt`:
- Line 45: Remove the optional [pub]? from the Assoc production so the grammar
matches parse_trait_decl_item and parse_impl_item, which dispatch associated
items only from Type or Fn and reject a leading Pub.

In `@src/parser/diagnostics.toml`:
- Around line 37-43: Remove the duplicate TOML table definitions for
impl_type_missing_body and const_item_without_value in the diagnostics
configuration, keeping exactly one header and its associated level/message
entries for each diagnostic so the file parses successfully.

In `@src/resolve/early.rs`:
- Around line 428-469: Extract a shared associated-item symbol helper for both
AssocItemKind::Fn and AssocItemKind::Type, then use it to collapse the
duplicated match arms in src/resolve/early.rs lines 428-469 and 546-570;
preserve each site’s existing allocation or insertion behavior. Reuse the helper
in src/resolve/late.rs lines 315-350 to remove the duplicated branching while
retaining its def_id_for_node mechanism.

In `@src/typeck/passes/collect.rs`:
- Around line 123-125: Update the associated-item collection logic around
AssocItemKind::Fn to handle associated type aliases instead of continuing past
all non-function items. Create and store a Scheme for each alias in
item_schemes, including the parent generic variables when applicable, so
Ty::normalize_aliases can resolve its associated-type DefId.

In `@src/typeck/types.rs`:
- Around line 125-136: Validate and complete generic arguments for the alias
before the substitution in the `item_schemes` branch, using the same
arity/default handling as `instantiate_with_explicit_args`. Ensure extra or
invalid arguments are rejected and omitted parameters receive valid mappings,
rather than allowing `zip` or an unmapped collector-owned `TyVarId` to normalize
the alias incorrectly.

---

Outside diff comments:
In `@src/parser/stmt.rs`:
- Around line 96-176: Update the TokenKind::Type branch in
parse_struct_decl_item to detect when the parsed associated type has no body
(type_ is None) and emit the new StructTypeMissingBody diagnostic at the
associated type name/span, while still adding the item. Add the corresponding
StructTypeMissingBody entry to parser diagnostics, following the existing
ImplTypeMissingBody and StructMethodMissingBody patterns.

In `@src/resolve/late.rs`:
- Around line 206-251: Update the Case 2 loop in defer_type_relative_path to
skip a prefix when resolve_module_path fails or when the module resolution lacks
the candidate type segment, rather than returning None. Preserve the existing
type-definition and trailing-segment checks, allowing all progressively shorter
prefixes to be tried before returning None.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: e83ec0cc-ec35-422c-9688-f6c509fee93d

📥 Commits

Reviewing files that changed from the base of the PR and between 3055466 and 9c41eed.

📒 Files selected for processing (29)
  • AGENTS.md
  • docs/grammar.txt
  • lib/oxi/std/ops.oxi
  • src/ast/mod.rs
  • src/ast/tests.rs
  • src/ast/validate.rs
  • src/ast/visit.rs
  • src/hir/def.rs
  • src/hir/lower/item.rs
  • src/hir/mod.rs
  • src/hir/types.rs
  • src/lexer/token.rs
  • src/parser/diagnostics.toml
  • src/parser/lookups.rs
  • src/parser/stmt.rs
  • src/resolve/early.rs
  • src/resolve/late.rs
  • src/resolve/mod.rs
  • src/thir/lower.rs
  • src/thir/mod.rs
  • src/thir/scope/builder.rs
  • src/typeck/mod.rs
  • src/typeck/passes/check/mod.rs
  • src/typeck/passes/collect.rs
  • src/typeck/types.rs
  • tests/integration/type_alias/chain.oxi
  • tests/integration/type_alias/generic.oxi
  • tests/integration/type_alias/invalid_rhs.oxi
  • tests/integration/type_alias/type_alias1.oxi

Comment thread docs/grammar.txt
Comment thread src/parser/diagnostics.toml
Comment thread src/resolve/early.rs Outdated
Comment thread src/typeck/passes/collect.rs Outdated
Comment thread src/typeck/types.rs Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/hir/lower/item.rs (1)

79-100: 🩺 Stability & Availability | 🔴 Critical | 🏗️ Heavy lift

Implement associated-type type checking before enabling this lowering.

A valid type Bar = i32; associated item reaches todo! branches in src/typeck/passes/collect.rs and src/typeck/passes/check/mod.rs, causing a compiler panic. Collect and check associated-type schemes, then add a positive integration test.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/hir/lower/item.rs` around lines 79 - 100, Before enabling the
associated-type lowering in the `AssocItemKind::Type` branch, implement
associated-type scheme collection in `collect.rs` and associated-type checking
in `check/mod.rs`, replacing the reachable `todo!` paths with the expected
type-checking behavior. Ensure valid declarations such as `type Bar = i32;`
complete without panicking, and add a positive integration test covering this
case.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/parser/diagnostics.toml`:
- Around line 21-23: Remove the duplicate [struct_assoc_type_missing_body] table
header from the diagnostics configuration, keeping a single definition with its
existing level and message so the TOML parses successfully.

In `@src/typeck/passes/check/mod.rs`:
- Around line 242-262: Update the generic-argument handling in the resolved-type
construction to return Ty::Error immediately after emitting
UnexpectedGenericArgs when args.len() differs from scheme.vars.len(). Only build
the mapping and call substitute_ty_vars for matching arity, preserving the
existing behavior for valid generic arguments.
- Around line 236-273: Update normalize_aliases to track TypeAlias def_ids
currently being expanded, detect self- and mutually-recursive re-entry before
recursively calling self.normalize_aliases, and emit the existing appropriate
cycle diagnostic instead of recursing indefinitely. Remove each alias from the
active-expansion set after expansion, preserving normal alias substitution, and
add a recursive alias case to the type-alias integration tests near invalid_rhs.

In `@src/typeck/passes/collect.rs`:
- Around line 168-170: The AssocItemKind::Type branches currently panic via
todo! instead of reporting unsupported associated types. In
src/typeck/passes/collect.rs lines 168-170, replace the todo! in
collect_signatures with associated-type scheme collection or a builders::emit_at
diagnostic; apply the same graceful handling in src/typeck/passes/check/mod.rs
lines 120-122 so body checking also avoids panics.

---

Outside diff comments:
In `@src/hir/lower/item.rs`:
- Around line 79-100: Before enabling the associated-type lowering in the
`AssocItemKind::Type` branch, implement associated-type scheme collection in
`collect.rs` and associated-type checking in `check/mod.rs`, replacing the
reachable `todo!` paths with the expected type-checking behavior. Ensure valid
declarations such as `type Bar = i32;` complete without panicking, and add a
positive integration test covering this case.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 82c36d8e-f3e4-4517-abb1-3d868c93d065

📥 Commits

Reviewing files that changed from the base of the PR and between 9c41eed and eafec0d.

📒 Files selected for processing (22)
  • crates/oxic_test/src/lib.rs
  • src/hir/lower/item.rs
  • src/hir/lower/mod.rs
  • src/hir/mod.rs
  • src/hir/owner.rs
  • src/hir/types.rs
  • src/parser/diagnostics.toml
  • src/parser/stmt.rs
  • src/parser/utils.rs
  • src/resolve/early.rs
  • src/resolve/late.rs
  • src/resolve/mod.rs
  • src/typeck/mod.rs
  • src/typeck/passes/check/mod.rs
  • src/typeck/passes/coherence.rs
  • src/typeck/passes/collect.rs
  • src/typeck/passes/method.rs
  • src/typeck/passes/rewrite.rs
  • tests/integration/deeply_nested_struct_method.oxi
  • tests/integration/generics/type_alias1.oxi
  • tests/integration/generics/type_alias2.oxi
  • tests/integration/struct_assoc_type_no_body.oxi
💤 Files with no reviewable changes (1)
  • src/hir/mod.rs

Comment thread src/parser/diagnostics.toml
Comment thread src/typeck/passes/check/mod.rs Outdated
Comment thread src/typeck/passes/check/mod.rs Outdated
Comment thread src/typeck/passes/collect.rs Outdated
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 22, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
src/typeck/passes/check/mod.rs (1)

270-285: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Instantiate associated-type schemes in the active inference context.

Line 285 caches scheme.body.clone(). That body can contain parent generic TyVarId values created during signature collection. check_bodies creates a new InferCtx and registers new variables before Self::A is checked.

For a generic associated type such as type A = T, Self::A can therefore resolve to stale or unrelated inference variables. This can mis-typecheck a generic associated function.

Keep the associated-type Scheme in the cache. Resolve its parent variables from the projection self type or the active BodyChecker inference context. Do not cache a context-specific instantiated Ty.

Add an integration case where a generic associated type directly aliases its parent parameter, such as type A = T, and use Self::A in an associated function.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/typeck/passes/check/mod.rs` around lines 270 - 285, Update
compute_assoc_types to cache each associated-type Scheme rather than
scheme.body.clone(), then instantiate or resolve its parent variables using the
projection self type or active BodyChecker inference context when Self::A is
checked. Ensure cached data is not tied to the signature-collection inference
context, and add an integration case where a generic associated type aliases its
parent parameter (type A = T) and an associated function uses Self::A.
src/typeck/types.rs (2)

479-507: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Reject or process generic arguments on intermediate path segments.

ty_hir_generic_args reads only the final segment. Its own example, Foo::<u8>::Bar::<u16>, shows that Foo::<u8> is silently discarded. This can resolve an associated type with incorrect outer generic arguments.

Walk every segment, or emit a diagnostic for non-final segment arguments until full support exists.

I can help implement the segment traversal and add an integration fixture.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/typeck/types.rs` around lines 479 - 507, Update ty_hir_generic_args to
inspect every path segment instead of silently ignoring generic_args on
intermediate segments; either process those arguments correctly or emit a
diagnostic for any non-final segment arguments while preserving final-segment
handling.

411-477: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Substitute earlier defaults into later associated-type defaults.

When no explicit generic arguments exist, each default is converted independently with ty_from_hir. For struct S<T = i32, U = T>, the second default is not substituted with T = i32. It becomes the current inference variable or an error value for T.

Reuse the substitution approach from fill_generic_defaults: resolve each default with the accumulated mapping, then add the resolved value to that mapping.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/typeck/types.rs` around lines 411 - 477, Update
resolve_inherent_assoc_type’s default-resolution branch to accumulate a
TyVarId-to-Ty mapping while processing defaults in declaration order. Before
calling ty_from_hir for each default, substitute the mapping accumulated from
earlier defaults into that default, then normalize and add the resolved value
under the corresponding scheme variable; preserve the existing recursion guard
and final substitute_ty_vars result.
src/typeck/mod.rs (1)

283-296: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Reuse canonicalized generic arguments in coherence checks.

Explicit generic args do not reuse hir_id_to_ty_var, so two non-default impls of the same trait get fresh Ty::Var ids and bypass has_conflicting_impl through raw equality. Normalize or canonicalize trait_generic_args and self_type_generic_args before inserting or comparing them.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/typeck/mod.rs` around lines 283 - 296, The coherence check in
has_conflicting_impl currently compares raw generic argument and self-type
values, allowing equivalent explicit non-default impls with different Ty::Var
IDs to bypass conflicts. Canonicalize or normalize trait_generic_args and
self_type_generic_args consistently before storing them in
impl_resolved_generic_args and impl_resolved_self_type, and compare the
canonical forms in has_conflicting_impl.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/typeck/types.rs`:
- Around line 283-285: Update projection resolution and normalization to use
Ty::Projection.generic_args alongside self_ty when matching implementation
candidates, including CoherenceTable lookups, consistency checks, and
ambiguity/in-progress keys. Ensure candidates with differing resolved trait
arguments are not conflated; report the existing overload error when multiple
matches differ, while preserving single-candidate behavior.

---

Outside diff comments:
In `@src/typeck/mod.rs`:
- Around line 283-296: The coherence check in has_conflicting_impl currently
compares raw generic argument and self-type values, allowing equivalent explicit
non-default impls with different Ty::Var IDs to bypass conflicts. Canonicalize
or normalize trait_generic_args and self_type_generic_args consistently before
storing them in impl_resolved_generic_args and impl_resolved_self_type, and
compare the canonical forms in has_conflicting_impl.

In `@src/typeck/passes/check/mod.rs`:
- Around line 270-285: Update compute_assoc_types to cache each associated-type
Scheme rather than scheme.body.clone(), then instantiate or resolve its parent
variables using the projection self type or active BodyChecker inference context
when Self::A is checked. Ensure cached data is not tied to the
signature-collection inference context, and add an integration case where a
generic associated type aliases its parent parameter (type A = T) and an
associated function uses Self::A.

In `@src/typeck/types.rs`:
- Around line 479-507: Update ty_hir_generic_args to inspect every path segment
instead of silently ignoring generic_args on intermediate segments; either
process those arguments correctly or emit a diagnostic for any non-final segment
arguments while preserving final-segment handling.
- Around line 411-477: Update resolve_inherent_assoc_type’s default-resolution
branch to accumulate a TyVarId-to-Ty mapping while processing defaults in
declaration order. Before calling ty_from_hir for each default, substitute the
mapping accumulated from earlier defaults into that default, then normalize and
add the resolved value under the corresponding scheme variable; preserve the
existing recursion guard and final substitute_ty_vars result.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1016898f-fa0e-4d0f-a506-a125cabdd2c6

📥 Commits

Reviewing files that changed from the base of the PR and between 67b6850 and d8166df.

📒 Files selected for processing (7)
  • src/typeck/mod.rs
  • src/typeck/passes/check/mod.rs
  • src/typeck/passes/collect.rs
  • src/typeck/types.rs
  • tests/integration/generics/projection_trait_partial_args.oxi
  • tests/integration/generics/projection_trait_wrong_generic_count.oxi
  • tests/integration/generics/self_type_generic_struct.oxi

Comment thread src/typeck/types.rs Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (10)
src/typeck/types.rs (2)

164-171: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Reject non-trailing generic defaults before counting required arguments.

position(|d| d.is_some()) sets the required count to the first default. A default before another non-defaulted generic parameter lets absent required arguments pass check_generic_arity, then fill_generic_defaults does not fill parameters after the None. Add AST validation that rejects a default before a later non-defaulted parameter, then check_generic_arity and fill_generic_defaults will work for trailing defaults.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/typeck/types.rs` around lines 164 - 171, Validate generic parameter
defaults in the AST to reject any defaulted parameter followed by a
non-defaulted parameter. Add this validation before the arity logic in
check_generic_arity, and ensure fill_generic_defaults relies on the resulting
trailing-default invariant while preserving normal handling of valid trailing
defaults.

341-356: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Store trait args and assoc-type args separately in Ty::Projection.

Ty::Projection.generic_args can contain <S as Trait<i32>>::Assoc's Trait argument i32, while S::Assoc leaves it None. Ty::Projection generic_args unification rejects Some/None as a mismatch, and normalization ignores it, so the same associated type can fail to unify. Store the two argument lists in separate fields, or use the same trait arguments for both spellings.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/typeck/types.rs` around lines 341 - 356, Update the projection
construction in the surrounding type conversion method so trait-path generic
arguments and associated-type segment arguments are represented separately in
Ty::Projection, or consistently reuse the trait arguments for both spellings.
Ensure S::Assoc and <S as Trait<i32>>::Assoc produce compatible projection types
during unification and normalization, rather than combining them with
segment_args.or(trait_path_args).
src/typeck/passes/check/mod.rs (1)

206-238: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Resolve default generic arguments before writing node_types.

resolve_default_generic_arg calls ty_from_hir, and TyKind::Infer allocates a fresh Ty::Var. This post-pass runs after the generic-default fallback loop, so such variables are not defaulted later. If any default argument still contains a variable, don’t insert the Ty::Adt substitution here.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/typeck/passes/check/mod.rs` around lines 206 - 238, Update the `resolved`
map construction around `resolve_default_generic_arg` so generic defaults
containing unresolved inference variables are not written back as a `Ty::Adt`
substitution. Before assigning `ty = Ty::Adt(*def_id, Some(args))`, detect
whether any resolved default argument still contains a variable and only apply
the substitution when all defaults are fully resolved and non-error.
src/typeck/passes/coherence.rs (3)

116-131: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

idx advances twice per iteration and can panic.

full_args grows by one element on each iteration (line 131), and idx re-reads full_args.len() on each iteration (line 119). The slice info.defaults[full_args.len()..] is bound once, so i already advances by one per iteration. The result is idx = base + 2*i instead of base + i.

Two consequences:

  • The substitution registers the default under the wrong generic parameter for the second and later defaults.
  • info.hir_ids[idx] panics with an out-of-bounds index. For a trait with three generic parameters and one supplied argument, base = 1, and the second iteration computes idx = 3 against a three-element hir_ids.

Capture the base offset before the loop.

🐛 Proposed fix
-                                for (i, default) in
-                                    info.defaults[full_args.len()..].iter().enumerate()
-                                {
-                                    let idx = full_args.len() + i;
+                                let base = full_args.len();
+                                for (i, default) in info.defaults[base..].iter().enumerate() {
+                                    let idx = base + i;
                                     let ty = this.resolve_default_generic_arg(
                                         default.as_ref().expect("default exists"),
                                         module_id,
                                         &subst,
                                         Some((trait_def_id, struct_def_id)),
                                     );
                                     if let Some(&var) =
                                         this.icx.hir_id_to_ty_var.get(&info.hir_ids[idx])
                                     {
                                         subst.insert(var, ty.clone());
                                     }
                                     full_args.push(ty);
                                 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/typeck/passes/coherence.rs` around lines 116 - 131, Capture the initial
full_args.len() before iterating over the sliced defaults, then compute each
hir_ids index from that fixed base plus i. Update the loop around
resolve_default_generic_arg so growing full_args does not affect idx, preserving
correct substitution for every default and avoiding out-of-bounds access.

219-227: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

This registration block is unreachable work.

collect_signatures already pushes every impl into coherence.impls and sets coherence.impl_to_trait (see src/typeck/passes/collect.rs lines 131-145). run() calls collect_signatures before check_coherence, so the contains(&def_id) guard is always true here and the body never runs.

Remove this block, or move impl registration out of collect_signatures so that only one pass owns it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/typeck/passes/coherence.rs` around lines 219 - 227, Remove the
unreachable impl-registration block in check_coherence’s surrounding flow, since
collect_signatures already populates coherence.impls and coherence.impl_to_trait
before it runs. Keep registration owned by only one pass and preserve the
existing coherence checking behavior.

173-218: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Emit conflicting impl diagnostics once per conflict.

has_conflicting_impl already ignores def_id, so both impls in a duplicate pair can emit ConflictingImplementations. Emit either only when def_id is later than the matched impl, or accumulate a conflict set before reporting.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/typeck/passes/coherence.rs` around lines 173 - 218, Update the
conflicting-implementation reporting around has_conflicting_impl so each
duplicate impl pair emits ConflictingImplementations only once. Use the impl IDs
collected in others to report only when def_id is later than the matched
conflicting impl, or otherwise accumulate and deduplicate conflicts before
calling builders::emit_at; preserve the existing diagnostic details and early
return behavior.
src/typeck/mod.rs (1)

149-180: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Two passes populate the same coherence tables. collect_signatures already fills coherence.generic_params, coherence.impls, and coherence.impl_to_trait, and run() calls it before both build_generic_params consumers and check_coherence. The other writers therefore either duplicate the work or are unreachable, and the duplicated generic_params writers already disagree about whether to insert an entry for an item with no generic parameters.

  • src/typeck/mod.rs#L149-L180: decide whether build_generic_params or collect_signatures owns coherence.generic_params, then remove the other writer. If build_generic_params stays, make collect_signatures stop re-inserting GenericParamInfo, and keep the unconditional-insert behavior so check_generic_arity sees a consistent map.
  • src/typeck/passes/coherence.rs#L219-L227: remove this block, because collect_signatures already pushed def_id into coherence.impls and set coherence.impl_to_trait, so the contains(&def_id) guard is always true.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/typeck/mod.rs` around lines 149 - 180, Remove the duplicate
coherence-table population: in src/typeck/mod.rs:149-180, keep
build_generic_params as the owner of coherence.generic_params, remove
collect_signatures’ re-insertion of GenericParamInfo, and preserve unconditional
insertion so check_generic_arity sees entries for non-generic items; in
src/typeck/passes/coherence.rs:219-227, remove the redundant impls/impl_to_trait
block guarded by contains(&def_id), since collect_signatures already populates
those tables.
src/typeck/passes/collect.rs (2)

439-449: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Group the threaded parameters into a context struct.

visit_hir_assoc_type_alias, walk_hir_ty_for_cycles, and walk_hir_qpath_for_cycles each take the same five context values plus two mutable sets, and each needs #[allow(clippy::too_many_arguments)]. Every recursive call repeats all eight arguments, which makes the call sites long and easy to get wrong.

Introduce a small struct that holds krate, assoc_type_index, assoc_to_parent, defs, visited, and in_progress, then pass &mut ctx plus start. The three #[allow] attributes can then be removed.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/typeck/passes/collect.rs` around lines 439 - 449, Introduce a context
struct containing krate, assoc_type_index, assoc_to_parent, defs, visited, and
in_progress, then update visit_hir_assoc_type_alias, walk_hir_ty_for_cycles, and
walk_hir_qpath_for_cycles to accept &mut context plus start instead of the
repeated parameters. Propagate the context through all recursive calls and
remove the three #[allow(clippy::too_many_arguments)] attributes while
preserving existing cycle-detection behavior.

298-311: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use an impl-aware key for the shared associated type lookup.

full_assoc_type_index is rebuilt into self.coherence.assoc_type_index, whose key is (struct_def_id, name). When one struct implements multiple traits with the same associated type name, later inserts replace earlier ones, so recursive associated types in the replaced impl may be missed. Key the lookup by the impl, or keep a separate composite key per impl, instead of reusing the trait-index key.

self.coherence.impls is an FxHashMap, so which entry remains is non-deterministic across runs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/typeck/passes/collect.rs` around lines 298 - 311, The rebuilt
full_assoc_type_index must distinguish associated types by impl as well as
struct and name, preventing same-named associated types from different trait
implementations from overwriting one another. Update the index key and all
corresponding lookup/use sites in the coherence collection flow, while
preserving coverage for recursive associated types across every impl in
self.coherence.impls.
src/typeck/passes/check/call.rs (1)

426-449: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Extract the shared auto-ref receiver decision.

Lines 426-449 in try_match_method_args and lines 504-527 in apply_auto_ref_adjustment implement the same rule: resolve the receiver and the first parameter, and if the receiver is neither a pointer nor a variable while the parameter is a pointer, unify against the pointer's inner type. The two copies differ only in what they do with the result, and both were touched here.

The probe uses the first copy to accept a candidate, and the finalization uses the second copy to record Adjustment::AutoRef. If the copies drift, the recorded adjustment stops matching the accepted candidate.

Extract a helper that returns the effective parameter type and whether auto-ref applies, then call it from both sites.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/typeck/passes/check/call.rs` around lines 426 - 449, Extract a shared
helper for the receiver/first-parameter auto-ref decision used by
try_match_method_args and apply_auto_ref_adjustment. Have it resolve both types,
detect the non-pointer/non-variable receiver with pointer parameter case, and
return the pointer’s inner type plus whether auto-ref applies; otherwise return
the original parameter type and false. Replace both duplicated branches with
this helper, preserving each caller’s existing result handling and
Adjustment::AutoRef recording.
♻️ Duplicate comments (2)
src/typeck/unify.rs (1)

158-174: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Ty::Alias still reaches the catch-all and reports a mismatch.

The projection arms normalize one side and retry. Ty::Alias has no arm, so (Ty::Alias { .. }, Ty::Adt(..)) falls to line 174 and produces a type mismatch. The Ty::Var arm at lines 47-52 also normalizes only Ty::Projection, so an alias bound to a variable stays unexpanded. normalize_assoc_projections already expands Ty::Alias, so symmetric alias arms would resolve these pairs.

This repeats an earlier review comment that is not marked as addressed.

🐛 Proposed alias arms
+            (Ty::Alias { .. }, _) => {
+                let a = self.normalize_assoc_projections(&a);
+                if matches!(&a, Ty::Alias { .. }) {
+                    Err(mismatch(a, b, span, module_id))
+                } else {
+                    self.unify(&a, &b, span, module_id)
+                }
+            }
+            (_, Ty::Alias { .. }) => {
+                let b = self.normalize_assoc_projections(&b);
+                if matches!(&b, Ty::Alias { .. }) {
+                    Err(mismatch(a, b, span, module_id))
+                } else {
+                    self.unify(&a, &b, span, module_id)
+                }
+            }
             _ => Err(mismatch(a, b, span, module_id)),

Run the following script to check whether a Ty::Alias can reach unify unexpanded:

#!/bin/bash
set -euo pipefail

echo "=== unify call sites outside unify.rs ==="
rg -nP --type=rust -C 6 '\.unify\s*\(' -g '!src/typeck/unify.rs'

echo
echo "=== paths that store Ty::Alias into schemes or node types without normalization ==="
rg -nP --type=rust -C 6 'Ty::Alias\s*\{' -g '!**/tests/**'

echo
echo "=== normalize_assoc_projections definition ==="
ast-grep run --pattern 'fn normalize_assoc_projections($$$) { $$$ }' --lang rust src/typeck
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/typeck/unify.rs` around lines 158 - 174, Update the unify matching logic
to add symmetric Ty::Alias arms alongside the existing Ty::Projection arms,
normalizing the alias-containing operand with normalize_assoc_projections and
retrying self.unify when expansion succeeds, otherwise returning mismatch. Also
update the Ty::Var normalization path so aliases bound to variables are
normalized, preserving the existing projection behavior.
src/typeck/types.rs (1)

108-114: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

The catch-all maps non-type definitions to Ty::Adt.

DefKind::TypeAlias becomes Ty::Alias. Every other kind becomes Ty::Adt(def_id, generic_args). A path in type position that resolves to a function, a constant, or an associated type therefore becomes an ADT whose DefId names a non-type. The failure surfaces later during unification or field lookup with a message that does not name the real problem.

An earlier review raised this and marked it addressed, but the arm is unchanged.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/typeck/types.rs` around lines 108 - 114, The catch-all arm in the
type-resolution match must reject non-type definitions instead of constructing
Ty::Adt. Update the match around resolver.def(def_id).kind to handle only valid
ADT definitions as Ty::Adt, preserve the TypeAlias-to-Ty::Alias path, and return
the established type-resolution error for functions, constants, associated
items, and other invalid kinds.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/typeck/mod.rs`:
- Around line 149-180: Remove the duplicate coherence-table population: in
src/typeck/mod.rs:149-180, keep build_generic_params as the owner of
coherence.generic_params, remove collect_signatures’ re-insertion of
GenericParamInfo, and preserve unconditional insertion so check_generic_arity
sees entries for non-generic items; in src/typeck/passes/coherence.rs:219-227,
remove the redundant impls/impl_to_trait block guarded by contains(&def_id),
since collect_signatures already populates those tables.

In `@src/typeck/passes/check/call.rs`:
- Around line 426-449: Extract a shared helper for the receiver/first-parameter
auto-ref decision used by try_match_method_args and apply_auto_ref_adjustment.
Have it resolve both types, detect the non-pointer/non-variable receiver with
pointer parameter case, and return the pointer’s inner type plus whether
auto-ref applies; otherwise return the original parameter type and false.
Replace both duplicated branches with this helper, preserving each caller’s
existing result handling and Adjustment::AutoRef recording.

In `@src/typeck/passes/check/mod.rs`:
- Around line 206-238: Update the `resolved` map construction around
`resolve_default_generic_arg` so generic defaults containing unresolved
inference variables are not written back as a `Ty::Adt` substitution. Before
assigning `ty = Ty::Adt(*def_id, Some(args))`, detect whether any resolved
default argument still contains a variable and only apply the substitution when
all defaults are fully resolved and non-error.

In `@src/typeck/passes/coherence.rs`:
- Around line 116-131: Capture the initial full_args.len() before iterating over
the sliced defaults, then compute each hir_ids index from that fixed base plus
i. Update the loop around resolve_default_generic_arg so growing full_args does
not affect idx, preserving correct substitution for every default and avoiding
out-of-bounds access.
- Around line 219-227: Remove the unreachable impl-registration block in
check_coherence’s surrounding flow, since collect_signatures already populates
coherence.impls and coherence.impl_to_trait before it runs. Keep registration
owned by only one pass and preserve the existing coherence checking behavior.
- Around line 173-218: Update the conflicting-implementation reporting around
has_conflicting_impl so each duplicate impl pair emits
ConflictingImplementations only once. Use the impl IDs collected in others to
report only when def_id is later than the matched conflicting impl, or otherwise
accumulate and deduplicate conflicts before calling builders::emit_at; preserve
the existing diagnostic details and early return behavior.

In `@src/typeck/passes/collect.rs`:
- Around line 439-449: Introduce a context struct containing krate,
assoc_type_index, assoc_to_parent, defs, visited, and in_progress, then update
visit_hir_assoc_type_alias, walk_hir_ty_for_cycles, and
walk_hir_qpath_for_cycles to accept &mut context plus start instead of the
repeated parameters. Propagate the context through all recursive calls and
remove the three #[allow(clippy::too_many_arguments)] attributes while
preserving existing cycle-detection behavior.
- Around line 298-311: The rebuilt full_assoc_type_index must distinguish
associated types by impl as well as struct and name, preventing same-named
associated types from different trait implementations from overwriting one
another. Update the index key and all corresponding lookup/use sites in the
coherence collection flow, while preserving coverage for recursive associated
types across every impl in self.coherence.impls.

In `@src/typeck/types.rs`:
- Around line 164-171: Validate generic parameter defaults in the AST to reject
any defaulted parameter followed by a non-defaulted parameter. Add this
validation before the arity logic in check_generic_arity, and ensure
fill_generic_defaults relies on the resulting trailing-default invariant while
preserving normal handling of valid trailing defaults.
- Around line 341-356: Update the projection construction in the surrounding
type conversion method so trait-path generic arguments and associated-type
segment arguments are represented separately in Ty::Projection, or consistently
reuse the trait arguments for both spellings. Ensure S::Assoc and <S as
Trait<i32>>::Assoc produce compatible projection types during unification and
normalization, rather than combining them with segment_args.or(trait_path_args).

---

Duplicate comments:
In `@src/typeck/types.rs`:
- Around line 108-114: The catch-all arm in the type-resolution match must
reject non-type definitions instead of constructing Ty::Adt. Update the match
around resolver.def(def_id).kind to handle only valid ADT definitions as
Ty::Adt, preserve the TypeAlias-to-Ty::Alias path, and return the established
type-resolution error for functions, constants, associated items, and other
invalid kinds.

In `@src/typeck/unify.rs`:
- Around line 158-174: Update the unify matching logic to add symmetric
Ty::Alias arms alongside the existing Ty::Projection arms, normalizing the
alias-containing operand with normalize_assoc_projections and retrying
self.unify when expansion succeeds, otherwise returning mismatch. Also update
the Ty::Var normalization path so aliases bound to variables are normalized,
preserving the existing projection behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 72319e86-3d30-46f0-a7ad-c7a32065ff9c

📥 Commits

Reviewing files that changed from the base of the PR and between d8166df and c4cb5b7.

📒 Files selected for processing (9)
  • src/typeck/mod.rs
  • src/typeck/passes/check/call.rs
  • src/typeck/passes/check/mod.rs
  • src/typeck/passes/coherence.rs
  • src/typeck/passes/collect.rs
  • src/typeck/types.rs
  • src/typeck/unify.rs
  • tests/integration/generics/assoc_type_inherent_default_chain.oxi
  • tests/integration/generics/projection_ambiguous_impl_args.oxi

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (7)
src/typeck/passes/check/call.rs (1)

352-361: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use auto-reference matching in the fallback path.

If a method takes &Self, this path unifies &Self directly with Self. A failed call can then emit a false receiver mismatch. Use receiver_auto_ref before this unification, as try_match_method_args does.

Proposed fix
 let first = param_tys.first().expect("method has at least 1 param");
+self
+    .typeck
+    .unify(&self.receiver_auto_ref(&recv_ty, first).0, &recv_ty, call_span, self.module_id)
- self.typeck
-     .unify(first, &recv_ty, call_span, self.module_id)
     .or_push_err(&mut self.typeck.icx);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/typeck/passes/check/call.rs` around lines 352 - 361, Update the method
receiver unification in the fallback path around the `is_method_call` block to
apply `receiver_auto_ref` to the receiver type before unifying it with the first
parameter, matching the behavior in `try_match_method_args`. Preserve the
existing argument unification and error propagation.
src/typeck/passes/check/mod.rs (3)

872-876: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Resolve dependent defaults against earlier arguments.

try_complete_generic_args copies the default HIR type without substituting prior arguments. For U = T, Foo::<i8> can lower U with the declaration-time T variable instead of i8. Resolve defaults sequentially with a substitution map from preceding parameters.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/typeck/passes/check/mod.rs` around lines 872 - 876, Update
try_complete_generic_args so each default type is resolved sequentially using
substitutions from previously supplied and completed arguments before being
appended to args. Build or reuse a substitution map keyed by preceding generic
parameters, apply it to default_ty, and update the map after each argument so
dependent defaults such as U = T resolve to the concrete earlier argument.

2005-2028: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Include trait generic arguments in projection diagnostics.

Ty::Projection discards trait_generic_args here. Diagnostics render both <S as A::<i8>>::Assoc and <S as A::<u8>>::Assoc as <S as A>::Assoc. Append the trait generic arguments after name.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/typeck/passes/check/mod.rs` around lines 2005 - 2028, Update the
Ty::Projection formatting branch to include its trait_generic_args after the
resolved trait name, while preserving the existing associated-type generic
arguments and fallback naming behavior. Ensure projections with different trait
arguments render distinctly, such as A::<i8> versus A::<u8>.

343-346: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Include generic arguments in projection recursion keys.

Both normalizers treat projections with different self type arguments or trait generic arguments as the same recursion entry. A valid chain from <S as A::<i8>>::Assoc to <S as A::<u8>>::Assoc can therefore stop as a false cycle.

  • src/typeck/passes/check/mod.rs#L343-L346: include the full projection identity in projections_in_progress.
  • src/typeck/passes/check/mod.rs#L541-L545: use the same full projection identity in body-checking normalization.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/typeck/passes/check/mod.rs` around lines 343 - 346, The projection
recursion keys used by both normalization paths omit generic arguments, causing
distinct projections to be treated as the same cycle: update
`src/typeck/passes/check/mod.rs` lines 343-346 and 541-545 to use the full
projection identity, including self type arguments and trait generic arguments,
in `projections_in_progress`; keep both paths consistent.
src/typeck/types.rs (2)

361-367: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

ty_display ignores trait_generic_args, so trait-argument mismatches print identical types.

unify_alias_args in src/typeck/unify.rs Lines 197-206 now reports a mismatch when two projections differ only in trait_generic_args. ty_display in src/typeck/passes/check/mod.rs Lines 2005-2027 destructures Ty::Projection with .. and never prints trait_generic_args. The mismatch diagnostic then shows the same text on both sides, for example <Foo as Multi>::Out versus <Foo as Multi>::Out.

Include trait_generic_args after the trait name in ty_display.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/typeck/types.rs` around lines 361 - 367, Update ty_display’s
Ty::Projection formatting to include trait_generic_args after the displayed
trait name, while preserving the existing self type, trait, and associated type
formatting. Ensure projections differing only in trait arguments render distinct
diagnostic text.

109-116: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Return an error for invalid type-position path resolutions.

is_type_def() accepts AssocType, but ty_from_hir()’s catch-all emits no diagnostic before returning Ty::Error. Since unify() accepts Ty::Error, this lets invalid type bindings continue without a reported error. Add a TyFromHirError variant or emit a diagnostic before returning Ty::Error. Trait paths already get ExpectedTypeFoundTrait during lowering, so this does not need to handle DefKind::Trait.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/typeck/types.rs` around lines 109 - 116, Update the type-position
resolution match in ty_from_hir() so invalid definitions such as
DefKind::AssocType produce a TyFromHirError or emit the appropriate diagnostic
before returning Ty::Error; preserve the existing TypeAlias and Struct handling,
and do not add separate Trait handling because lowering already reports it.
src/typeck/passes/coherence.rs (1)

305-316: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Normalize default projections after substitutions.

In resolve_default_generic_arg, normalize_type_alias(&ty) can only resolve a Ty::Projection when self_ty is Ty::Adt. When a default projects over an earlier generic arg, that arg is substituted after normalization, so the projection stays unresolved in the returned type. If the projection can be resolved later, SubstituteTy, unify it again; otherwise Ty::Projection leaks into generics.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/typeck/passes/coherence.rs` around lines 305 - 316, Update
resolve_default_generic_arg to perform normalize_type_alias after applying subst
and self_subst, so projections over substituted generic arguments can resolve
once self_ty becomes a Ty::Adt. Re-run substitution or unification as needed to
resolve any newly normalized result, and ensure unresolved projections do not
leak into the returned generic type.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/ast/diagnostics.toml`:
- Around line 37-39: Remove the duplicate [generic_default_before] table
declaration in diagnostics.toml, keeping a single header while preserving its
existing level and message entries so diagnostic loading succeeds.

In `@src/typeck/types.rs`:
- Around line 370-385: Update shorthand_trait_args and the related projection
argument flow so traits without defaults use the same normalized
trait_generic_args representation as fully qualified paths, rather than
returning None; alternatively, infer the missing arguments from the selected
impl before unify_alias_args and impl_matching_trait_args compare or select
candidates. Preserve default filling for traits whose parameters all have
defaults and ensure ambiguous impls are resolved using their impl arguments.

In `@src/typeck/unify.rs`:
- Around line 167-182: Add unit tests covering both Ty::Alias arms in the typeck
test module: verify unexpandable aliases produce mismatches on either side, and
aliases with a Scheme entry in item_schemes expand and unify with their concrete
type. Also update the Ty::Projection handling near the existing projection arm
to normalize both operands when the left operand is an alias, while preserving
the current mismatch result.

---

Outside diff comments:
In `@src/typeck/passes/check/call.rs`:
- Around line 352-361: Update the method receiver unification in the fallback
path around the `is_method_call` block to apply `receiver_auto_ref` to the
receiver type before unifying it with the first parameter, matching the behavior
in `try_match_method_args`. Preserve the existing argument unification and error
propagation.

In `@src/typeck/passes/check/mod.rs`:
- Around line 872-876: Update try_complete_generic_args so each default type is
resolved sequentially using substitutions from previously supplied and completed
arguments before being appended to args. Build or reuse a substitution map keyed
by preceding generic parameters, apply it to default_ty, and update the map
after each argument so dependent defaults such as U = T resolve to the concrete
earlier argument.
- Around line 2005-2028: Update the Ty::Projection formatting branch to include
its trait_generic_args after the resolved trait name, while preserving the
existing associated-type generic arguments and fallback naming behavior. Ensure
projections with different trait arguments render distinctly, such as A::<i8>
versus A::<u8>.
- Around line 343-346: The projection recursion keys used by both normalization
paths omit generic arguments, causing distinct projections to be treated as the
same cycle: update `src/typeck/passes/check/mod.rs` lines 343-346 and 541-545 to
use the full projection identity, including self type arguments and trait
generic arguments, in `projections_in_progress`; keep both paths consistent.

In `@src/typeck/passes/coherence.rs`:
- Around line 305-316: Update resolve_default_generic_arg to perform
normalize_type_alias after applying subst and self_subst, so projections over
substituted generic arguments can resolve once self_ty becomes a Ty::Adt. Re-run
substitution or unification as needed to resolve any newly normalized result,
and ensure unresolved projections do not leak into the returned generic type.

In `@src/typeck/types.rs`:
- Around line 361-367: Update ty_display’s Ty::Projection formatting to include
trait_generic_args after the displayed trait name, while preserving the existing
self type, trait, and associated type formatting. Ensure projections differing
only in trait arguments render distinct diagnostic text.
- Around line 109-116: Update the type-position resolution match in
ty_from_hir() so invalid definitions such as DefKind::AssocType produce a
TyFromHirError or emit the appropriate diagnostic before returning Ty::Error;
preserve the existing TypeAlias and Struct handling, and do not add separate
Trait handling because lowering already reports it.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 9ea3a207-9985-40cf-b61a-15dec2dd5035

📥 Commits

Reviewing files that changed from the base of the PR and between c4cb5b7 and b4f6a1d.

📒 Files selected for processing (16)
  • src/ast/diagnostics.toml
  • src/ast/validate.rs
  • src/typeck/fold.rs
  • src/typeck/passes/check/call.rs
  • src/typeck/passes/check/mod.rs
  • src/typeck/passes/coherence.rs
  • src/typeck/passes/collect.rs
  • src/typeck/types.rs
  • src/typeck/unify.rs
  • tests/integration/generics/partial_explicit_args_trait_defaults.oxi
  • tests/integration/generics/partial_explicit_args_trait_defaults_mismatch.oxi
  • tests/integration/generics/struct_generic_default_before.oxi
  • tests/integration/generics/trait_generic_default_before.oxi
  • tests/integration/traits/assoc_type_trait_generic_arg_select.oxi
  • tests/integration/traits/assoc_type_trait_generic_arg_wrong.oxi
  • tests/integration/traits/trait_default_assoc_shorthand.oxi

Comment thread src/ast/diagnostics.toml
Comment thread src/typeck/types.rs Outdated
Comment thread src/typeck/unify.rs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/typeck/passes/check/call.rs (1)

213-218: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Validate only method generic arguments.

scheme.vars includes parent impl or trait variables. Explicit call arguments map only to method_vars. For impl<T> Foo<T> { fn f<U>(...) }, foo.f::<i32>() is rejected because probing expects two arguments. Conversely, extra arguments can pass validation and then be dropped by zip(method_vars).

  • src/typeck/passes/check/call.rs#L213-L218: Complete and validate explicit arguments against the method-variable count.
  • src/typeck/passes/check/mod.rs#L926-L945: Derive method_vars before completion and map exactly that list.

Add a regression for an explicit generic method inside a generic impl.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/typeck/passes/check/call.rs` around lines 213 - 218, Validate explicit
call generic arguments against method_vars rather than scheme.vars, so parent
impl or trait variables are excluded and extra arguments are rejected instead of
truncated. In src/typeck/passes/check/call.rs lines 213-218, update
try_complete_generic_args to use the method-variable count; in
src/typeck/passes/check/mod.rs lines 926-945, derive method_vars before
completion and map arguments exactly to that list. Add a regression covering an
explicit generic method declared inside a generic impl.
♻️ Duplicate comments (1)
src/typeck/types.rs (1)

312-320: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Instantiate associated-type generic arguments during resolution.

segment.generic_args is not available when inherent associated types resolve. The projection normalizers also discard Ty::Projection.generic_args, while compute_assoc_types retains only an uninstantiated body. A declaration such as type Item<T> = T can therefore resolve Foo::Item::<i32> to a collector-owned type variable instead of i32.

  • src/typeck/types.rs#L312-L320: Convert and pass segment.generic_args into inherent associated-type resolution.
  • src/typeck/passes/check/mod.rs#L261-L284: Preserve sufficient associated-type scheme data to instantiate its generic parameters.
  • src/typeck/passes/check/mod.rs#L322-L360: Apply projection generic arguments before normalizing the selected associated type.
  • src/typeck/passes/check/mod.rs#L527-L609: Apply the same substitution in fallible body-check normalization and include these arguments in the recursion key.

Add regressions for inherent and trait associated types with generic arguments.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/typeck/types.rs` around lines 312 - 320, Instantiate associated-type
generic arguments throughout resolution and normalization. In
src/typeck/types.rs:312-320, convert segment.generic_args and pass them to
resolve_inherent_assoc_type. In src/typeck/passes/check/mod.rs:261-284, retain
the associated-type scheme needed to instantiate generic parameters; in 322-360
and 527-609, apply projection arguments before normalization and include them in
the fallible normalization recursion key. Add regressions covering generic
inherent and trait associated types.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/typeck/passes/check/call.rs`:
- Around line 213-218: Validate explicit call generic arguments against
method_vars rather than scheme.vars, so parent impl or trait variables are
excluded and extra arguments are rejected instead of truncated. In
src/typeck/passes/check/call.rs lines 213-218, update try_complete_generic_args
to use the method-variable count; in src/typeck/passes/check/mod.rs lines
926-945, derive method_vars before completion and map arguments exactly to that
list. Add a regression covering an explicit generic method declared inside a
generic impl.

---

Duplicate comments:
In `@src/typeck/types.rs`:
- Around line 312-320: Instantiate associated-type generic arguments throughout
resolution and normalization. In src/typeck/types.rs:312-320, convert
segment.generic_args and pass them to resolve_inherent_assoc_type. In
src/typeck/passes/check/mod.rs:261-284, retain the associated-type scheme needed
to instantiate generic parameters; in 322-360 and 527-609, apply projection
arguments before normalization and include them in the fallible normalization
recursion key. Add regressions covering generic inherent and trait associated
types.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 65e013cd-e04c-4c9c-91ba-cd12f074e2ac

📥 Commits

Reviewing files that changed from the base of the PR and between b4f6a1d and 1835c15.

📒 Files selected for processing (5)
  • src/typeck/passes/check/call.rs
  • src/typeck/passes/check/mod.rs
  • src/typeck/passes/coherence.rs
  • src/typeck/types.rs
  • src/typeck/unify.rs

@coderabbitai coderabbitai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/typeck/passes/check/mod.rs`:
- Around line 48-67: Change ProjectionRecKey to store the identifying projection
values directly—trait_def_id, assoc_def_id, self_ty, trait_generic_args, and
generic_args—instead of a u64 hash, preserving suitable Clone, PartialEq, and Eq
derives. Update its constructor to build that tuple-backed key without hashing,
and adjust guard-vector contains and retain usages in normalize_aliases_inner
and normalize_assoc_projections_inner to borrow the non-Copy key.
🪄 Autofix

❌ Autofix failed (check again to retry)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: a4a9ee7e-cb11-4feb-bf46-cb022761fdb0

📥 Commits

Reviewing files that changed from the base of the PR and between b4f6a1d and ea5f036.

📒 Files selected for processing (12)
  • src/ast/mod.rs
  • src/hir/mod.rs
  • src/typeck/passes/check/call.rs
  • src/typeck/passes/check/mod.rs
  • src/typeck/passes/coherence.rs
  • src/typeck/types.rs
  • src/typeck/unify.rs
  • tests/integration/generics/assoc_type_inherent_generic_args.oxi
  • tests/integration/generics/method_explicit_type_args_in_generic_impl.oxi
  • tests/integration/generics/method_explicit_type_args_in_generic_impl_wrong_count.oxi
  • tests/integration/traits/assoc_type_generic_struct.oxi
  • tests/integration/traits/assoc_type_proj_generic_args.oxi

Comment thread src/typeck/passes/check/mod.rs Outdated
@coderabbitai

coderabbitai Bot commented Aug 9, 2026 •

Copy link
Copy Markdown
Contributor

An unexpected error occurred while generating fixes: Not Found - https://docs.github.com/rest/git/refs#get-a-reference

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/typeck/passes/check/mod.rs (1)

1210-1239: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Instantiate dependent generic defaults before use.

The completed defaults are converted without substituting earlier resolved arguments. A declaration such as struct Pair<T, U = T> can therefore retain the declaration-level variable for U when callers provide only T.

  • src/typeck/passes/check/mod.rs#L1210-L1239: Convert completed struct arguments in order. Substitute prior resolved arguments into each default.
  • src/typeck/passes/check/mod.rs#L1276-L1296: Build an alias substitution map from provided arguments. Apply it before appending each alias default.
  • src/typeck/passes/check/mod.rs#L1352-L1360: Apply the target struct substitution map before appending omitted target arguments.
  • src/typeck/passes/check/mod.rs#L1372-L1380: Map target generic variables to fresh variables before resolving and storing defaults.

Add coverage for direct and alias-expanded initialization with U = T.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/typeck/passes/check/mod.rs` around lines 1210 - 1239, Update the generic
argument handling in src/typeck/passes/check/mod.rs at lines 1210-1239,
1276-1296, 1352-1360, and 1372-1380: resolve completed struct defaults in order
by substituting previously resolved arguments, build alias substitutions from
provided arguments before appending alias defaults, apply target struct
substitutions before omitted target arguments, and map target generic variables
to fresh variables before resolving stored defaults. Preserve direct and
alias-expanded initialization behavior and add coverage for defaults such as U =
T.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/typeck/passes/check/mod.rs`:
- Around line 1210-1239: Update the generic argument handling in
src/typeck/passes/check/mod.rs at lines 1210-1239, 1276-1296, 1352-1360, and
1372-1380: resolve completed struct defaults in order by substituting previously
resolved arguments, build alias substitutions from provided arguments before
appending alias defaults, apply target struct substitutions before omitted
target arguments, and map target generic variables to fresh variables before
resolving stored defaults. Preserve direct and alias-expanded initialization
behavior and add coverage for defaults such as U = T.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b9d2f82e-85b8-4eda-b779-7fa377fbf5ad

📥 Commits

Reviewing files that changed from the base of the PR and between ea5f036 and f063dd1.

📒 Files selected for processing (2)
  • src/typeck/passes/check/mod.rs
  • src/typeck/types.rs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/typeck/passes/check/mod.rs`:
- Around line 1284-1295: In the type-checking flow containing the
resolved-argument loop, validate whether args.len() exceeds scheme.vars.len()
before iterating and indexing alias_info.hir_ids[i]. Reuse the existing
UnexpectedGenericArgs diagnostic and return StructInitDef::Error immediately,
while preserving normal substitution and resolution for valid argument counts.
- Around line 1378-1387: Update the omitted-argument loop in the type-checking
pass to insert each newly created target generic variable into subst using its
corresponding declared variable before resolving that parameter’s default type.
Ensure later defaults resolve through these fresh variables, including chained
defaults such as U = T and V = U, and add a regression test covering a partial
target-generic alias.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 37410330-e50c-4081-98fa-3328db6ff986

📥 Commits

Reviewing files that changed from the base of the PR and between f063dd1 and b6a005f.

📒 Files selected for processing (6)
  • src/typeck/passes/check/mod.rs
  • tests/integration/generics/default_complete_chain.oxi
  • tests/integration/generics/default_complete_chain_error.oxi
  • tests/integration/type_alias/struct_init_bare_alias_chain.oxi
  • tests/integration/type_alias/struct_init_default_chain.oxi
  • tests/integration/type_alias/struct_init_default_chain_error.oxi

Comment thread src/typeck/passes/check/mod.rs
Comment thread src/typeck/passes/check/mod.rs
@septechx

septechx commented Aug 9, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/typeck/passes/check/mod.rs (1)

1374-1394: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Validate target generic arity before indexing info.hir_ids.

An alias RHS can contain more generic arguments than struct_def declares. The loop at Line 1383 indexes info.hir_ids[i] before any target-arity validation. This can panic the compiler instead of emitting UnexpectedGenericArgs.

Add an args.len() > info.hir_ids.len() check before the first loop. Emit the existing diagnostic and return StructInitDef::Error.

Proposed fix
                 if let Some(info) = &struct_info {
+                    if args.len() > info.hir_ids.len() {
+                        emit_unexpected_generic_args(
+                            self.typeck.ctx,
+                            span,
+                            self.module_id,
+                            info.hir_ids.len(),
+                            args.len(),
+                        );
+                        return StructInitDef::Error;
+                    }
                     let mut subst: FxHashMap<TyVarId, Ty> = FxHashMap::default();

The conversion path in src/typeck/types.rs:548-550 converts each HIR generic argument before this branch.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/typeck/passes/check/mod.rs` around lines 1374 - 1394, Validate target
generic arity in the Ty::Adt branch before the loop that indexes info.hir_ids:
when args.len() exceeds info.hir_ids.len(), emit the existing
UnexpectedGenericArgs diagnostic and return StructInitDef::Error. Keep normal
substitution and inference unchanged for valid arities.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/typeck/passes/check/mod.rs`:
- Around line 1374-1394: Validate target generic arity in the Ty::Adt branch
before the loop that indexes info.hir_ids: when args.len() exceeds
info.hir_ids.len(), emit the existing UnexpectedGenericArgs diagnostic and
return StructInitDef::Error. Keep normal substitution and inference unchanged
for valid arities.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8a67be62-bfae-444e-8099-0bb22d7805f9

📥 Commits

Reviewing files that changed from the base of the PR and between b6a005f and ec83f2f.

📒 Files selected for processing (3)
  • src/typeck/passes/check/mod.rs
  • tests/integration/type_alias/struct_init_partial_target_chain.oxi
  • tests/integration/type_alias/struct_init_partial_target_chain_error.oxi

@septechx

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 12, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/typeck/passes/check/mod.rs (3)

595-601: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Match trait generic arguments before using current_assoc_types.

This fast path checks current_self_ty but ignores trait_generic_args. For an implementation such as impl Trait<u32> for Foo, a projection such as <Self as Trait<bool>>::Assoc has the same receiver and can resolve to the Trait<u32> associated type. The fallback beginning at Line 608 performs the trait-argument match, but this branch bypasses it. Store or recover the current implementation's trait arguments before using current_assoc_types, or restrict this fast path to projections whose trait arguments are known to match.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/typeck/passes/check/mod.rs` around lines 595 - 601, Update the fast path
constructing resolved in the current_self_ty/current_assoc_types branch to also
verify that the projection’s trait_generic_args match the current
implementation’s trait arguments before retrieving the associated type. Recover
or store those implementation arguments as needed, and otherwise fall through to
the existing argument-aware resolution beginning at the fallback path.

1013-1051: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Normalize type aliases before accepting a qpath receiver.

After icx.resolve, base can still be Ty::Alias. The function then returns None because it does not call normalize_type_alias, so receiver lookup through a type alias cannot find methods or associated items. check_member_access already normalizes the analogous receiver at Line 1824.

Proposed fix
-        let base = self.typeck.icx.resolve(&base);
+        let base = self.typeck.icx.resolve(&base);
+        let base = self.typeck.normalize_type_alias(&base);
         if matches!(base, Ty::Adt(_, _)) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/typeck/passes/check/mod.rs` around lines 1013 - 1051, After resolving
base in the qpath receiver flow, normalize it with the existing type-alias
normalization helper before continuing receiver lookup. Update the logic around
the base computation in the enclosing method, matching check_member_access’s
existing normalization behavior so Ty::Alias receivers can resolve methods and
associated items.

1363-1368: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Report alias-normalization errors before returning StructInitDef::Error.

normalize_aliases returns TyFromHirError, but the let Ok(body) = ... else branch discards it. check_struct_init then returns Ty::Error without emitting a diagnostic. Invalid projections or aliases used in a struct initializer can therefore fail silently.

Proposed fix
-        let Ok(body) = self.normalize_aliases(body, span) else {
-            return StructInitDef::Error;
-        };
+        let body = match self.normalize_aliases(body, span) {
+            Ok(body) => body,
+            Err(err) => {
+                self.report_ty_from_hir_error(err);
+                return StructInitDef::Error;
+            }
+        };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/typeck/passes/check/mod.rs` around lines 1363 - 1368, Update the
normalize_aliases handling in check_struct_init to retain the
Err(TyFromHirError) value and report it through the existing type-checking
diagnostic path before returning StructInitDef::Error. Preserve the current
successful normalization flow and error return behavior after emitting the
diagnostic.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/typeck/passes/check/mod.rs`:
- Around line 595-601: Update the fast path constructing resolved in the
current_self_ty/current_assoc_types branch to also verify that the projection’s
trait_generic_args match the current implementation’s trait arguments before
retrieving the associated type. Recover or store those implementation arguments
as needed, and otherwise fall through to the existing argument-aware resolution
beginning at the fallback path.
- Around line 1013-1051: After resolving base in the qpath receiver flow,
normalize it with the existing type-alias normalization helper before continuing
receiver lookup. Update the logic around the base computation in the enclosing
method, matching check_member_access’s existing normalization behavior so
Ty::Alias receivers can resolve methods and associated items.
- Around line 1363-1368: Update the normalize_aliases handling in
check_struct_init to retain the Err(TyFromHirError) value and report it through
the existing type-checking diagnostic path before returning
StructInitDef::Error. Preserve the current successful normalization flow and
error return behavior after emitting the diagnostic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 7c5c10ab-6e80-4675-a628-a881c33454d6

📥 Commits

Reviewing files that changed from the base of the PR and between ec83f2f and e4327ae.

📒 Files selected for processing (1)
  • src/typeck/passes/check/mod.rs

@septechx

septechx commented Oct 5, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant