Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 5 additions & 10 deletions compiler/rustc_ast_lowering/src/delegation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {

// FIXME(fn_delegation): proper support for parent generics propagation
// in method call scenario.
let segment = self.process_segment(span, &segment, &mut generics.child, false);
let segment = self.process_segment(span, &segment, &mut generics.child);
let segment = self.arena.alloc(segment);

self.arena.alloc(hir::Expr {
Expand All @@ -534,14 +534,10 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {

new_path.segments = self.arena.alloc_from_iter(
new_path.segments.iter().enumerate().map(|(idx, segment)| {
let mut process_segment = |result, add_lifetimes| {
self.process_segment(span, segment, result, add_lifetimes)
};

if idx + 2 == len {
process_segment(&mut generics.parent, true)
self.process_segment(span, segment, &mut generics.parent)
} else if idx + 1 == len {
process_segment(&mut generics.child, false)
self.process_segment(span, segment, &mut generics.child)
} else {
segment.clone()
}
Expand All @@ -551,7 +547,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
hir::QPath::Resolved(ty, self.arena.alloc(new_path))
}
hir::QPath::TypeRelative(ty, segment) => {
let segment = self.process_segment(span, segment, &mut generics.child, false);
let segment = self.process_segment(span, segment, &mut generics.child);

hir::QPath::TypeRelative(ty, self.arena.alloc(segment))
}
Expand Down Expand Up @@ -584,13 +580,12 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
span: Span,
segment: &hir::PathSegment<'hir>,
result: &mut GenericsGenerationResult<'hir>,
add_lifetimes: bool,
) -> hir::PathSegment<'hir> {
let details = result.generics.args_propagation_details();

let segment = if details.should_propagate {
let generics = result.generics.into_hir_generics(self, span);
let args = generics.into_generic_args(self, add_lifetimes, span);
let args = generics.into_generic_args(self, span);

// Needed for better error messages (`trait-impl-wrong-args-count.rs` test).
let args = if args.is_empty() { None } else { Some(args) };
Expand Down
83 changes: 65 additions & 18 deletions compiler/rustc_ast_lowering/src/delegation/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use rustc_hir::def_id::DefId;
use rustc_middle::ty::GenericParamDefKind;
use rustc_middle::{bug, ty};
use rustc_span::symbol::kw;
use rustc_span::{Ident, Span};
use rustc_span::{Ident, Span, sym};

use crate::{LoweringContext, ResolverAstLoweringExt};

Expand All @@ -25,22 +25,37 @@ pub(super) enum DelegationGenericsKind {
TraitImpl(bool /* Has user-specified args */),
}

#[derive(Debug, Clone, Copy)]
pub(super) enum GenericsPosition {
Parent,
Child,
}

pub(super) struct DelegationGenerics<T> {
generics: T,
kind: DelegationGenericsKind,
pos: GenericsPosition,
}

impl<'hir> DelegationGenerics<&'hir [ty::GenericParamDef]> {
fn default(generics: &'hir [ty::GenericParamDef]) -> Self {
DelegationGenerics { generics, kind: DelegationGenericsKind::Default }
fn default(generics: &'hir [ty::GenericParamDef], pos: GenericsPosition) -> Self {
DelegationGenerics { generics, pos, kind: DelegationGenericsKind::Default }
}

fn user_specified(generics: &'hir [ty::GenericParamDef]) -> Self {
DelegationGenerics { generics, kind: DelegationGenericsKind::UserSpecified }
fn user_specified(generics: &'hir [ty::GenericParamDef], pos: GenericsPosition) -> Self {
DelegationGenerics { generics, pos, kind: DelegationGenericsKind::UserSpecified }
}

fn trait_impl(generics: &'hir [ty::GenericParamDef], user_specified: bool) -> Self {
DelegationGenerics { generics, kind: DelegationGenericsKind::TraitImpl(user_specified) }
fn trait_impl(
generics: &'hir [ty::GenericParamDef],
user_specified: bool,
pos: GenericsPosition,
) -> Self {
DelegationGenerics {
generics,
pos,
kind: DelegationGenericsKind::TraitImpl(user_specified),
}
}
}

Expand Down Expand Up @@ -103,8 +118,14 @@ impl<'hir> HirOrTyGenerics<'hir> {
span: Span,
) -> &mut HirOrTyGenerics<'hir> {
if let HirOrTyGenerics::Ty(ty) = self {
let params = ctx.uplift_delegation_generic_params(span, ty.generics);
*self = HirOrTyGenerics::Hir(DelegationGenerics { generics: params, kind: ty.kind });
let rename_self = matches!(ty.pos, GenericsPosition::Child);
let params = ctx.uplift_delegation_generic_params(span, ty.generics, rename_self);

*self = HirOrTyGenerics::Hir(DelegationGenerics {
generics: params,
kind: ty.kind,
pos: ty.pos,
});
}

self
Expand All @@ -120,14 +141,14 @@ impl<'hir> HirOrTyGenerics<'hir> {
pub(super) fn into_generic_args(
&self,
ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
add_lifetimes: bool,
span: Span,
) -> &'hir hir::GenericArgs<'hir> {
match self {
HirOrTyGenerics::Ty(_) => {
bug!("Attempting to get generic args before uplifting to HIR")
}
HirOrTyGenerics::Hir(hir) => {
let add_lifetimes = matches!(hir.pos, GenericsPosition::Parent);
ctx.create_generics_args_from_params(hir.generics.params, add_lifetimes, span)
}
}
Expand Down Expand Up @@ -227,10 +248,15 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
if matches!(delegation_parent_kind, DefKind::Impl { of_trait: true }) {
// Considering parent generics, during signature inheritance
// we will take those args that are in trait impl header trait ref.
let parent = DelegationGenerics::trait_impl(&[], true);
let parent = DelegationGenerics::trait_impl(&[], true, GenericsPosition::Parent);
let parent = GenericsGenerationResult::new(parent);

let child = DelegationGenerics::trait_impl(sig_params, child_user_specified);
let child = DelegationGenerics::trait_impl(
sig_params,
child_user_specified,
GenericsPosition::Child,
);

let child = GenericsGenerationResult::new(child);

return GenericsGenerationResults {
Expand Down Expand Up @@ -263,25 +289,32 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
DelegationGenerics {
kind: DelegationGenericsKind::SelfAndUserSpecified,
generics: &sig_parent_params[..1],
pos: GenericsPosition::Parent,
}
} else {
DelegationGenerics::user_specified(&[])
DelegationGenerics::user_specified(&[], GenericsPosition::Parent)
}
} else {
let skip_self = usize::from(!generate_self);
DelegationGenerics::default(&sig_parent_params[skip_self..])
DelegationGenerics::default(
&sig_parent_params[skip_self..],
GenericsPosition::Parent,
)
}
} else {
DelegationGenerics::default(&[])
DelegationGenerics::default(&[], GenericsPosition::Parent)
};

let child_generics = if child_user_specified {
let synth_params_index =
sig_params.iter().position(|p| p.kind.is_synthetic()).unwrap_or(sig_params.len());

DelegationGenerics::user_specified(&sig_params[synth_params_index..])
DelegationGenerics::user_specified(
&sig_params[synth_params_index..],
GenericsPosition::Child,
)
} else {
DelegationGenerics::default(sig_params)
DelegationGenerics::default(sig_params, GenericsPosition::Child)
};

GenericsGenerationResults {
Expand All @@ -296,6 +329,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
&mut self,
span: Span,
params: &'hir [ty::GenericParamDef],
rename_self: bool,
) -> &'hir hir::Generics<'hir> {
let params = self.arena.alloc_from_iter(params.iter().map(|p| {
let def_kind = match p.kind {
Expand All @@ -304,7 +338,20 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
GenericParamDefKind::Const { .. } => DefKind::ConstParam,
};

let param_ident = Ident::new(p.name, span);
// Rename Self generic param to This so it is properly propagated.
// If the user will create a function `fn foo<Self>() {}` with generic
// param "Self" then it will not be generated in HIR, the same thing
// applies to traits, `trait Trait<Self> {}` will be represented as
// `trait Trait {}` in HIR and "unexpected keyword `Self` in generic parameters"
// error will be emitted.
// Note that we do not rename `Self` to `This` after non-recursive reuse
// from Trait, in this case the `Self` should not be propagated
// (we rely that implicit `Self` generic param of a trait is named "Self")
// and it is OK to have Self generic param generated during lowering.
let param_name =
if rename_self && p.name == kw::SelfUpper { sym::This } else { p.name };

let param_ident = Ident::new(param_name, span);
let def_name = Some(param_ident.name);
let node_id = self.next_node_id();

Expand Down
28 changes: 14 additions & 14 deletions compiler/rustc_const_eval/src/interpret/intern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,7 @@
use hir::def::DefKind;
use rustc_ast::Mutability;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_hir::def_id::LocalDefIdMap;
use rustc_hir::definitions::{
DefPathData, PerParentDisambiguatorState, PerParentDisambiguatorsMap,
};
use rustc_hir::definitions::{DefPathData, PerParentDisambiguatorState};
use rustc_hir::{self as hir};
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::mir::interpret::{
Expand Down Expand Up @@ -108,7 +105,7 @@ fn intern_shallow<'tcx, M: CompileTimeMachine<'tcx>>(
ecx: &mut InterpCx<'tcx, M>,
alloc_id: AllocId,
mutability: Mutability,
disambiguators: Option<&mut LocalDefIdMap<PerParentDisambiguatorState>>,
disambiguator: Option<&mut PerParentDisambiguatorState>,
) -> Result<impl Iterator<Item = CtfeProvenance> + 'tcx, InternError> {
trace!("intern_shallow {:?}", alloc_id);
// remove allocation
Expand All @@ -132,7 +129,7 @@ fn intern_shallow<'tcx, M: CompileTimeMachine<'tcx>>(
static_id,
alloc_id,
alloc,
disambiguators.expect("disambiguators needed"),
disambiguator.expect("disambiguator needed"),
);
} else {
ecx.tcx.set_alloc_id_memory(alloc_id, alloc);
Expand All @@ -147,19 +144,18 @@ fn intern_as_new_static<'tcx>(
static_id: LocalDefId,
alloc_id: AllocId,
alloc: ConstAllocation<'tcx>,
disambiguators: &mut LocalDefIdMap<PerParentDisambiguatorState>,
disambiguator: &mut PerParentDisambiguatorState,
) {
// `intern_const_alloc_recursive` is called once per static and it contains the `DisambiguatorState`.
// `intern_const_alloc_recursive` is called once per static and it contains the `PerParentDisambiguatorState`.
// The `<static_id>::{{nested}}` path is thus unique to `intern_const_alloc_recursive` and the
// `DisambiguatorState` ensures the generated path is unique for this call as we generate
// `PerParentDisambiguatorState` ensures the generated path is unique for this call as we generate
// `<static_id>::{{nested#n}}` where `n` is the `n`th `intern_as_new_static` call.
let feed = tcx.create_def(
static_id,
None,
DefKind::Static { safety: hir::Safety::Safe, mutability: alloc.0.mutability, nested: true },
Some(DefPathData::NestedStatic),
//FIXME(oli-obk): cleanup (https://github.com/rust-lang/rust/pull/155547#discussion_r3110792640)
disambiguators.get_or_create(static_id),
disambiguator,
);
tcx.set_nested_alloc_id_static(alloc_id, feed.def_id());

Expand Down Expand Up @@ -209,7 +205,9 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx>>(
intern_kind: InternKind,
ret: &MPlaceTy<'tcx>,
) -> Result<(), InternError> {
let mut disambiguators = Default::default();
let mut disambiguator =
ecx.machine.static_def_id().map(|id| PerParentDisambiguatorState::new(id));
let mut disambiguator = disambiguator.as_mut();

// We are interning recursively, and for mutability we are distinguishing the "root" allocation
// that we are starting in, and all other allocations that we are encountering recursively.
Expand Down Expand Up @@ -248,13 +246,15 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx>>(
// This gives us the initial set of nested allocations, which will then all be processed
// recursively in the loop below.
let mut todo: Vec<_> = if is_static {
assert!(disambiguator.is_some());
// Do not steal the root allocation, we need it later to create the return value of `eval_static_initializer`.
// But still change its mutability to match the requested one.
let (kind, alloc) = ecx.memory.alloc_map.get_mut(&base_alloc_id).unwrap();
prepare_alloc(*ecx.tcx, *kind, alloc, base_mutability)?;
alloc.provenance().ptrs().iter().map(|&(_, prov)| prov).collect()
} else {
intern_shallow(ecx, base_alloc_id, base_mutability, Some(&mut disambiguators))?.collect()
assert!(disambiguator.is_none());
intern_shallow(ecx, base_alloc_id, base_mutability, None)?.collect()
};
// We need to distinguish "has just been interned" from "was already in `tcx`",
// so we track this in a separate set.
Expand Down Expand Up @@ -336,7 +336,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx>>(
// okay with losing some potential for immutability here. This can anyway only affect
// `static mut`.
just_interned.insert(alloc_id);
let next = intern_shallow(ecx, alloc_id, inner_mutability, Some(&mut disambiguators))?;
let next = intern_shallow(ecx, alloc_id, inner_mutability, disambiguator.as_deref_mut())?;
todo.extend(next);
}
if found_bad_mutable_ptr {
Expand Down
5 changes: 0 additions & 5 deletions compiler/rustc_session/src/config/print_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,6 @@ pub enum PrintKind {
}

impl PrintKind {
/// FIXME: rust-analyzer doesn't support `#![feature(macro_derive)]` yet
/// (<https://github.com/rust-lang/rust-analyzer/issues/21043>), which breaks autocomplete.
/// Work around that by aliasing the trait constant to a regular constant.
const ALL_VARIANTS: &[Self] = <Self as AllVariants>::ALL_VARIANTS;

fn name(self) -> &'static str {
use PrintKind::*;
match self {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
if impl_candidates.len() < 40 {
self.report_similar_impl_candidates(
impl_candidates.as_slice(),
obligation,
trait_pred,
obligation.cause.body_id,
&mut err,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1973,6 +1973,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
pub(super) fn report_similar_impl_candidates(
&self,
impl_candidates: &[ImplCandidate<'tcx>],
obligation: &PredicateObligation<'tcx>,
trait_pred: ty::PolyTraitPredicate<'tcx>,
body_def_id: LocalDefId,
err: &mut Diag<'_>,
Expand Down Expand Up @@ -2037,6 +2038,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
};

if let [single] = &impl_candidates {
let self_ty = trait_pred.skip_binder().self_ty();
if !self_ty.has_escaping_bound_vars() {
let self_ty = self.tcx.instantiate_bound_regions_with_erased(trait_pred.self_ty());
if let ty::Ref(_, inner_ty, _) = self_ty.kind()
&& self.can_eq(param_env, single.trait_ref.self_ty(), *inner_ty)
&& !self.where_clause_expr_matches_failed_self_ty(obligation, self_ty)
{
// Avoid pointing at a nearby impl like `String: Borrow<str>` when the
// failing obligation comes from something nested inside an enclosing call
// expression such as `foo(&[String::from("a")])`.
return true;
}
}

// If we have a single implementation, try to unify it with the trait ref
// that failed. This should uncover a better hint for what *is* implemented.
if self.probe(|_| {
Expand Down Expand Up @@ -2456,6 +2471,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let impl_candidates = self.find_similar_impl_candidates(trait_pred);
self.report_similar_impl_candidates(
&impl_candidates,
obligation,
trait_pred,
body_def_id,
err,
Expand Down Expand Up @@ -3137,6 +3153,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let impl_candidates = self.find_similar_impl_candidates(trait_predicate);
if !self.report_similar_impl_candidates(
&impl_candidates,
obligation,
trait_predicate,
body_def_id,
err,
Expand Down
Loading
Loading