Skip to content

Commit 112f2f5

Browse files
committed
Auto merge of #153507 - JonathanBrouwer:rollup-ki59UTE, r=JonathanBrouwer
Rollup of 14 pull requests Successful merges: - rust-lang/rust#153466 (`rust-analyzer` subtree update) - rust-lang/rust#151280 (Fix incorrect trailing comma suggested in no_accessible_fields) - rust-lang/rust#152593 (Box in `ValTreeKind::Branch(Box<[I::Const]>)` changed to `List`) - rust-lang/rust#153174 (std: add wasm64 to sync::Once and thread_parking atomics cfg guards) - rust-lang/rust#153485 (libcore float tests: replace macro shadowing by const-compatible macro) - rust-lang/rust#153495 (Fix ICE in `offset_of!` error recovery) - rust-lang/rust#152040 (Do not emit ConstEvaluatable goals if type-const) - rust-lang/rust#152741 (Suppress invalid suggestions in destructuring assignment) - rust-lang/rust#153189 (refactor: move `check_align` to `parse_alignment`) - rust-lang/rust#153230 (Roll rustfmt reviewers for in-tree rustfmt) - rust-lang/rust#153445 (Consider try blocks as block-like for overflowed expr) - rust-lang/rust#153452 (Cleanup unused diagnostic emission methods) - rust-lang/rust#153476 (bootstrap.py: fix typo "parallle") - rust-lang/rust#153483 (Preserve parentheses around `Fn` trait bounds in pretty printer)
2 parents b477a05 + a6fc78b commit 112f2f5

34 files changed

Lines changed: 817 additions & 207 deletions

File tree

.codecov.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
coverage:
2+
range: 40...60
3+
status:
4+
patch: off
5+
project:
6+
default:
7+
informational: true
8+
9+
# Don't leave comments on PRs
10+
comment: false

.github/workflows/coverage.yaml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: Coverage
2+
3+
on: [pull_request, push]
4+
5+
env:
6+
CARGO_INCREMENTAL: 0
7+
CARGO_NET_RETRY: 10
8+
CI: 1
9+
RUST_BACKTRACE: short
10+
RUSTUP_MAX_RETRIES: 10
11+
12+
jobs:
13+
coverage:
14+
runs-on: ubuntu-latest
15+
steps:
16+
- uses: actions/checkout@v4
17+
18+
- name: Install Rust toolchain
19+
run: |
20+
rustup update --no-self-update nightly
21+
rustup default nightly
22+
rustup component add --toolchain nightly rust-src rustc-dev rustfmt
23+
# We also install a nightly rustfmt, because we use `--file-lines` in
24+
# a test.
25+
rustup toolchain install nightly --profile minimal --component rustfmt
26+
27+
rustup toolchain install nightly --component llvm-tools-preview
28+
29+
- name: Install cargo-llvm-cov
30+
uses: taiki-e/install-action@cargo-llvm-cov
31+
32+
- name: Install nextest
33+
uses: taiki-e/install-action@nextest
34+
35+
- name: Generate code coverage
36+
run: cargo llvm-cov --workspace --lcov --output-path lcov.info
37+
38+
- name: Upload coverage to Codecov
39+
uses: codecov/codecov-action@v5
40+
with:
41+
files: lcov.info
42+
fail_ci_if_error: false
43+
token: ${{ secrets.CODECOV_TOKEN }}
44+
verbose: true

AGENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
CLAUDE.md

CLAUDE.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
**Reminder: All AI usage must be disclosed in commit messages, see
2+
CONTRIBUTING.md for more details.**
3+
4+
## Build Commands
5+
6+
```bash
7+
cargo build # Build all crates
8+
cargo test # Run all tests
9+
cargo test -p <crate> # Run tests for a specific crate (e.g., cargo test -p hir-ty)
10+
cargo lint # Run clippy on all targets
11+
cargo xtask codegen # Run code generation
12+
cargo xtask tidy # Run tidy checks
13+
UPDATE_EXPECT=1 cargo test # Update test expectations (snapshot tests)
14+
RUN_SLOW_TESTS=1 cargo test # Run heavy/slow tests
15+
```
16+
17+
## Key Architectural Invariants
18+
19+
- Typing in a function body never invalidates global derived data
20+
- Parser/syntax tree is built per-file to enable parallel parsing
21+
- The server is stateless (HTTP-like); context must be re-created from request parameters
22+
- Cancellation uses salsa's cancellation mechanism; computations panic with a `Cancelled` payload
23+
24+
### Code Generation
25+
26+
Generated code is committed to the repo. Grammar and AST are generated from `ungrammar`. Run `cargo test -p xtask` after adding inline parser tests (`// test test_name` comments).
27+
28+
## Testing
29+
30+
Tests are snapshot-based using `expect-test`. Test fixtures use a mini-language:
31+
- `$0` marks cursor position
32+
- `// ^^^^` labels attach to the line above
33+
- `//- minicore: sized, fn` includes parts of minicore (minimal core library)
34+
- `//- /path/to/file.rs crate:name deps:dep1,dep2` declares files/crates
35+
36+
## Style Notes
37+
38+
- Use `stdx::never!` and `stdx::always!` instead of `assert!` for recoverable invariants
39+
- Use `T![fn]` macro instead of `SyntaxKind::FN_KW`
40+
- Use keyword name mangling over underscore prefixing for identifiers: `crate``krate`, `fn``func`, `struct``strukt`, `type``ty`

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/hir-def/src/visibility.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ impl Visibility {
234234
if mod_.krate(db) == krate { Some(Visibility::Module(mod_, exp)) } else { None }
235235
}
236236
(Visibility::Module(mod_a, expl_a), Visibility::Module(mod_b, expl_b)) => {
237-
if mod_a.krate(db) != mod_b.krate(db) {
237+
if mod_a == mod_b {
238238
// Most module visibilities are `pub(self)`, and assuming no errors
239239
// this will be the common and thus fast path.
240240
return Some(Visibility::Module(

crates/hir-expand/src/builtin/fn_macro.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,7 @@ use std::borrow::Cow;
55
use base_db::AnchoredPath;
66
use cfg::CfgExpr;
77
use either::Either;
8-
use intern::{
9-
Symbol,
10-
sym,
11-
};
8+
use intern::{Symbol, sym};
129
use itertools::Itertools;
1310
use mbe::{DelimiterKind, expect_fragment};
1411
use span::{Edition, FileId, Span};

crates/hir-ty/src/infer/expr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -658,7 +658,7 @@ impl<'db> InferenceContext<'_, 'db> {
658658
}
659659
}
660660
if let RecordSpread::Expr(expr) = *spread {
661-
self.infer_expr(expr, &Expectation::has_type(ty), ExprIsRead::Yes);
661+
self.infer_expr_coerce_never(expr, &Expectation::has_type(ty), ExprIsRead::Yes);
662662
}
663663
ty
664664
}

crates/hir-ty/src/infer/op.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,9 @@ impl<'a, 'db> InferenceContext<'a, 'db> {
178178
// trait matching creating lifetime constraints that are too strict.
179179
// e.g., adding `&'a T` and `&'b T`, given `&'x T: Add<&'x T>`, will result
180180
// in `&'a T <: &'x T` and `&'b T <: &'x T`, instead of `'a = 'b = 'x`.
181-
let lhs_ty = self.infer_expr_no_expect(lhs_expr, ExprIsRead::No);
181+
let lhs_ty = self.infer_expr_no_expect(lhs_expr, ExprIsRead::Yes);
182182
let fresh_var = self.table.next_ty_var();
183-
self.demand_coerce(lhs_expr, lhs_ty, fresh_var, AllowTwoPhase::No, ExprIsRead::No)
183+
self.demand_coerce(lhs_expr, lhs_ty, fresh_var, AllowTwoPhase::No, ExprIsRead::Yes)
184184
}
185185
};
186186
let lhs_ty = self.table.resolve_vars_with_obligations(lhs_ty);
@@ -200,7 +200,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> {
200200

201201
// see `NB` above
202202
let rhs_ty =
203-
self.infer_expr_coerce(rhs_expr, &Expectation::HasType(rhs_ty_var), ExprIsRead::No);
203+
self.infer_expr_coerce(rhs_expr, &Expectation::HasType(rhs_ty_var), ExprIsRead::Yes);
204204
let rhs_ty = self.table.resolve_vars_with_obligations(rhs_ty);
205205

206206
let return_ty = match result {
@@ -320,7 +320,11 @@ impl<'a, 'db> InferenceContext<'a, 'db> {
320320
if let Some((rhs_expr, rhs_ty)) = opt_rhs
321321
&& rhs_ty.is_ty_var()
322322
{
323-
self.infer_expr_coerce(rhs_expr, &Expectation::HasType(rhs_ty), ExprIsRead::No);
323+
self.infer_expr_coerce(
324+
rhs_expr,
325+
&Expectation::HasType(rhs_ty),
326+
ExprIsRead::Yes,
327+
);
324328
}
325329

326330
// Construct an obligation `self_ty : Trait<input_tys>`

crates/hir-ty/src/lower.rs

Lines changed: 70 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,7 @@ use rustc_hash::FxHashSet;
4040
use rustc_type_ir::{
4141
AliasTyKind, BoundVarIndexKind, ConstKind, DebruijnIndex, ExistentialPredicate,
4242
ExistentialProjection, ExistentialTraitRef, FnSig, Interner, OutlivesPredicate, TermKind,
43-
TyKind,
44-
TypeFoldable, TypeVisitableExt, Upcast, UpcastFrom, elaborate,
43+
TyKind, TypeFoldable, TypeVisitableExt, Upcast, UpcastFrom, elaborate,
4544
inherent::{Clause as _, GenericArgs as _, IntoKind as _, Region as _, Ty as _},
4645
};
4746
use smallvec::SmallVec;
@@ -1681,10 +1680,16 @@ impl SupertraitsInfo {
16811680
}
16821681
}
16831682

1684-
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1685-
enum TypeParamAssocTypeShorthandError {
1686-
AssocTypeNotFound,
1687-
AmbiguousAssocType,
1683+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1684+
enum AssocTypeShorthandResolution {
1685+
Resolved(StoredEarlyBinder<(TypeAliasId, StoredGenericArgs)>),
1686+
Ambiguous {
1687+
/// If one resolution belongs to a sub-trait and one to a supertrait, this contains
1688+
/// the sub-trait's resolution. This can be `None` if there is no trait inheritance
1689+
/// relationship between the resolutions.
1690+
sub_trait_resolution: Option<StoredEarlyBinder<(TypeAliasId, StoredGenericArgs)>>,
1691+
},
1692+
NotFound,
16881693
Cycle,
16891694
}
16901695

@@ -1708,7 +1713,7 @@ fn resolve_type_param_assoc_type_shorthand(
17081713
def: GenericDefId,
17091714
param: TypeParamId,
17101715
assoc_name: Name,
1711-
) -> Result<StoredEarlyBinder<(TypeAliasId, StoredGenericArgs)>, TypeParamAssocTypeShorthandError> {
1716+
) -> AssocTypeShorthandResolution {
17121717
let generics = generics(db, def);
17131718
let resolver = def.resolver(db);
17141719
let mut ctx = TyLoweringContext::new(
@@ -1719,13 +1724,13 @@ fn resolve_type_param_assoc_type_shorthand(
17191724
LifetimeElisionKind::AnonymousReportError,
17201725
);
17211726
let interner = ctx.interner;
1722-
let mut result = None;
17231727
let param_ty = Ty::new_param(
17241728
interner,
17251729
param,
17261730
generics.type_or_const_param_idx(param.into()).unwrap() as u32,
17271731
);
17281732

1733+
let mut this_trait_resolution = None;
17291734
if let GenericDefId::TraitId(containing_trait) = param.parent()
17301735
&& param.local_id() == GenericParams::SELF_PARAM_ID_IN_SELF
17311736
{
@@ -1734,10 +1739,11 @@ fn resolve_type_param_assoc_type_shorthand(
17341739
containing_trait.trait_items(db).associated_type_by_name(&assoc_name)
17351740
{
17361741
let args = GenericArgs::identity_for_item(interner, containing_trait.into());
1737-
result = Some(StoredEarlyBinder::bind((assoc_type, args.store())));
1742+
this_trait_resolution = Some(StoredEarlyBinder::bind((assoc_type, args.store())));
17381743
}
17391744
}
17401745

1746+
let mut supertraits_resolution = None;
17411747
for maybe_parent_generics in
17421748
std::iter::successors(Some(&generics), |generics| generics.parent_generics())
17431749
{
@@ -1783,34 +1789,53 @@ fn resolve_type_param_assoc_type_shorthand(
17831789
TypeParamId::trait_self(bounded_trait),
17841790
assoc_name.clone(),
17851791
);
1786-
let lookup_on_bounded_trait = match lookup_on_bounded_trait {
1787-
Ok(it) => it,
1788-
Err(
1789-
err @ (TypeParamAssocTypeShorthandError::AmbiguousAssocType
1790-
| TypeParamAssocTypeShorthandError::Cycle),
1791-
) => return Err(*err),
1792-
Err(TypeParamAssocTypeShorthandError::AssocTypeNotFound) => {
1792+
let assoc_type_and_args = match &lookup_on_bounded_trait {
1793+
AssocTypeShorthandResolution::Resolved(trait_ref) => trait_ref,
1794+
AssocTypeShorthandResolution::Ambiguous {
1795+
sub_trait_resolution: Some(trait_ref),
1796+
} => trait_ref,
1797+
AssocTypeShorthandResolution::Ambiguous { sub_trait_resolution: None } => {
1798+
return AssocTypeShorthandResolution::Ambiguous {
1799+
sub_trait_resolution: this_trait_resolution,
1800+
};
1801+
}
1802+
AssocTypeShorthandResolution::NotFound => {
17931803
never!("we checked that the trait defines this assoc type");
17941804
continue;
17951805
}
1806+
AssocTypeShorthandResolution::Cycle => return AssocTypeShorthandResolution::Cycle,
17961807
};
1797-
let (assoc_type, args) = lookup_on_bounded_trait
1798-
.get_with(|(assoc_type, args)| (*assoc_type, args.as_ref()))
1799-
.skip_binder();
1800-
let args = EarlyBinder::bind(args).instantiate(interner, bounded_trait_ref.args);
1801-
let current_result = StoredEarlyBinder::bind((assoc_type, args.store()));
1802-
// If we already have a result, this is an ambiguity - unless this is the same result, then we are fine
1803-
// (e.g. rustc allows to write the same bound twice without ambiguity).
1804-
if let Some(existing_result) = result
1805-
&& existing_result != current_result
1806-
{
1807-
return Err(TypeParamAssocTypeShorthandError::AmbiguousAssocType);
1808+
if let Some(this_trait_resolution) = this_trait_resolution {
1809+
return AssocTypeShorthandResolution::Ambiguous {
1810+
sub_trait_resolution: Some(this_trait_resolution),
1811+
};
1812+
} else if supertraits_resolution.is_some() {
1813+
return AssocTypeShorthandResolution::Ambiguous { sub_trait_resolution: None };
1814+
} else {
1815+
let (assoc_type, args) = assoc_type_and_args
1816+
.get_with(|(assoc_type, args)| (*assoc_type, args.as_ref()))
1817+
.skip_binder();
1818+
let args = EarlyBinder::bind(args).instantiate(interner, bounded_trait_ref.args);
1819+
let current_result = StoredEarlyBinder::bind((assoc_type, args.store()));
1820+
supertraits_resolution = Some(match lookup_on_bounded_trait {
1821+
AssocTypeShorthandResolution::Resolved(_) => {
1822+
AssocTypeShorthandResolution::Resolved(current_result)
1823+
}
1824+
AssocTypeShorthandResolution::Ambiguous { .. } => {
1825+
AssocTypeShorthandResolution::Ambiguous {
1826+
sub_trait_resolution: Some(current_result),
1827+
}
1828+
}
1829+
AssocTypeShorthandResolution::NotFound
1830+
| AssocTypeShorthandResolution::Cycle => unreachable!(),
1831+
});
18081832
}
1809-
result = Some(current_result);
18101833
}
18111834
}
18121835

1813-
result.ok_or(TypeParamAssocTypeShorthandError::AssocTypeNotFound)
1836+
supertraits_resolution
1837+
.or_else(|| this_trait_resolution.map(AssocTypeShorthandResolution::Resolved))
1838+
.unwrap_or(AssocTypeShorthandResolution::NotFound)
18141839
}
18151840

18161841
fn resolve_type_param_assoc_type_shorthand_cycle_result(
@@ -1819,8 +1844,8 @@ fn resolve_type_param_assoc_type_shorthand_cycle_result(
18191844
_def: GenericDefId,
18201845
_param: TypeParamId,
18211846
_assoc_name: Name,
1822-
) -> Result<StoredEarlyBinder<(TypeAliasId, StoredGenericArgs)>, TypeParamAssocTypeShorthandError> {
1823-
Err(TypeParamAssocTypeShorthandError::Cycle)
1847+
) -> AssocTypeShorthandResolution {
1848+
AssocTypeShorthandResolution::Cycle
18241849
}
18251850

18261851
#[inline]
@@ -2468,7 +2493,7 @@ fn fn_sig_for_struct_constructor(
24682493
let inputs_and_output =
24692494
Tys::new_from_iter(DbInterner::new_no_crate(db), params.chain(Some(ret.as_ref())));
24702495
StoredEarlyBinder::bind(StoredPolyFnSig::new(Binder::dummy(FnSig {
2471-
abi: FnAbi::RustCall,
2496+
abi: FnAbi::Rust,
24722497
c_variadic: false,
24732498
safety: Safety::Safe,
24742499
inputs_and_output,
@@ -2487,7 +2512,7 @@ fn fn_sig_for_enum_variant_constructor(
24872512
let inputs_and_output =
24882513
Tys::new_from_iter(DbInterner::new_no_crate(db), params.chain(Some(ret.as_ref())));
24892514
StoredEarlyBinder::bind(StoredPolyFnSig::new(Binder::dummy(FnSig {
2490-
abi: FnAbi::RustCall,
2515+
abi: FnAbi::Rust,
24912516
c_variadic: false,
24922517
safety: Safety::Safe,
24932518
inputs_and_output,
@@ -2569,19 +2594,22 @@ pub(crate) fn associated_ty_item_bounds<'db>(
25692594
EarlyBinder::bind(BoundExistentialPredicates::new_from_slice(&bounds))
25702595
}
25712596

2572-
pub(crate) fn associated_type_by_name_including_super_traits<'db>(
2597+
pub(crate) fn associated_type_by_name_including_super_traits_allow_ambiguity<'db>(
25732598
db: &'db dyn HirDatabase,
25742599
trait_ref: TraitRef<'db>,
25752600
name: Name,
25762601
) -> Option<(TypeAliasId, GenericArgs<'db>)> {
2577-
let assoc_type = resolve_type_param_assoc_type_shorthand(
2578-
db,
2579-
trait_ref.def_id.0.into(),
2580-
TypeParamId::trait_self(trait_ref.def_id.0),
2581-
name.clone(),
2582-
)
2583-
.as_ref()
2584-
.ok()?;
2602+
let (AssocTypeShorthandResolution::Resolved(assoc_type)
2603+
| AssocTypeShorthandResolution::Ambiguous { sub_trait_resolution: Some(assoc_type) }) =
2604+
resolve_type_param_assoc_type_shorthand(
2605+
db,
2606+
trait_ref.def_id.0.into(),
2607+
TypeParamId::trait_self(trait_ref.def_id.0),
2608+
name.clone(),
2609+
)
2610+
else {
2611+
return None;
2612+
};
25852613
let (assoc_type, trait_args) = assoc_type
25862614
.get_with(|(assoc_type, trait_args)| (*assoc_type, trait_args.as_ref()))
25872615
.skip_binder();

0 commit comments

Comments
 (0)