Type-check generic const items
This commit is contained in:
parent
da17134be0
commit
8c390286e4
4 changed files with 122 additions and 103 deletions
|
@ -76,7 +76,7 @@ fn check_method_is_structurally_compatible<'tcx>(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function is best explained by example. Consider a trait with it's implementation:
|
/// This function is best explained by example. Consider a trait with its implementation:
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// trait Trait<'t, T> {
|
/// trait Trait<'t, T> {
|
||||||
|
@ -120,7 +120,7 @@ fn check_method_is_structurally_compatible<'tcx>(
|
||||||
/// types:
|
/// types:
|
||||||
///
|
///
|
||||||
/// ```rust,ignore (pseudo-Rust)
|
/// ```rust,ignore (pseudo-Rust)
|
||||||
/// <'b> fn(t: &'i0 U0, m: &'b) -> Foo
|
/// <'b> fn(t: &'i0 U0, m: &'b N0) -> Foo
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// We now want to extract and substitute the type of the *trait*
|
/// We now want to extract and substitute the type of the *trait*
|
||||||
|
@ -137,7 +137,7 @@ fn check_method_is_structurally_compatible<'tcx>(
|
||||||
/// Applying this to the trait method type yields:
|
/// Applying this to the trait method type yields:
|
||||||
///
|
///
|
||||||
/// ```rust,ignore (pseudo-Rust)
|
/// ```rust,ignore (pseudo-Rust)
|
||||||
/// <'a> fn(t: &'i0 U0, m: &'a) -> Foo
|
/// <'a> fn(t: &'i0 U0, m: &'a N0) -> Foo
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// This type is also the same but the name of the bound region (`'a`
|
/// This type is also the same but the name of the bound region (`'a`
|
||||||
|
@ -258,8 +258,6 @@ fn compare_method_predicate_entailment<'tcx>(
|
||||||
// type.
|
// type.
|
||||||
|
|
||||||
// Compute placeholder form of impl and trait method tys.
|
// Compute placeholder form of impl and trait method tys.
|
||||||
let tcx = infcx.tcx;
|
|
||||||
|
|
||||||
let mut wf_tys = FxIndexSet::default();
|
let mut wf_tys = FxIndexSet::default();
|
||||||
|
|
||||||
let unnormalized_impl_sig = infcx.instantiate_binder_with_fresh_vars(
|
let unnormalized_impl_sig = infcx.instantiate_binder_with_fresh_vars(
|
||||||
|
@ -1668,19 +1666,19 @@ fn compare_synthetic_generics<'tcx>(
|
||||||
/// ```rust,ignore (pseudo-Rust)
|
/// ```rust,ignore (pseudo-Rust)
|
||||||
/// trait Foo {
|
/// trait Foo {
|
||||||
/// fn foo<const N: u8>();
|
/// fn foo<const N: u8>();
|
||||||
/// type bar<const N: u8>;
|
/// type Bar<const N: u8>;
|
||||||
/// fn baz<const N: u32>();
|
/// fn baz<const N: u32>();
|
||||||
/// type blah<T>;
|
/// type Blah<T>;
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// impl Foo for () {
|
/// impl Foo for () {
|
||||||
/// fn foo<const N: u64>() {}
|
/// fn foo<const N: u64>() {}
|
||||||
/// //~^ error
|
/// //~^ error
|
||||||
/// type bar<const N: u64> {}
|
/// type Bar<const N: u64> = ();
|
||||||
/// //~^ error
|
/// //~^ error
|
||||||
/// fn baz<T>() {}
|
/// fn baz<T>() {}
|
||||||
/// //~^ error
|
/// //~^ error
|
||||||
/// type blah<const N: i64> = u32;
|
/// type Blah<const N: i64> = u32;
|
||||||
/// //~^ error
|
/// //~^ error
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -1769,36 +1767,82 @@ pub(super) fn compare_impl_const_raw(
|
||||||
let trait_const_item = tcx.associated_item(trait_const_item_def);
|
let trait_const_item = tcx.associated_item(trait_const_item_def);
|
||||||
let impl_trait_ref =
|
let impl_trait_ref =
|
||||||
tcx.impl_trait_ref(impl_const_item.container_id(tcx)).unwrap().instantiate_identity();
|
tcx.impl_trait_ref(impl_const_item.container_id(tcx)).unwrap().instantiate_identity();
|
||||||
debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
|
|
||||||
|
|
||||||
let impl_c_span = tcx.def_span(impl_const_item_def.to_def_id());
|
debug!("compare_impl_const(impl_trait_ref={:?})", impl_trait_ref);
|
||||||
|
|
||||||
let infcx = tcx.infer_ctxt().build();
|
compare_number_of_generics(tcx, impl_const_item, trait_const_item, false)?;
|
||||||
let param_env = tcx.param_env(impl_const_item_def.to_def_id());
|
compare_generic_param_kinds(tcx, impl_const_item, trait_const_item, false)?;
|
||||||
let ocx = ObligationCtxt::new(&infcx);
|
compare_const_predicate_entailment(tcx, impl_const_item, trait_const_item, impl_trait_ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The equivalent of [compare_method_predicate_entailment], but for associated constants
|
||||||
|
/// instead of associated functions.
|
||||||
|
// FIXME(generic_const_items): If possible extract the common parts of `compare_{type,const}_predicate_entailment`.
|
||||||
|
fn compare_const_predicate_entailment<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
impl_ct: ty::AssocItem,
|
||||||
|
trait_ct: ty::AssocItem,
|
||||||
|
impl_trait_ref: ty::TraitRef<'tcx>,
|
||||||
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
|
let impl_ct_def_id = impl_ct.def_id.expect_local();
|
||||||
|
let impl_ct_span = tcx.def_span(impl_ct_def_id);
|
||||||
|
|
||||||
// The below is for the most part highly similar to the procedure
|
// The below is for the most part highly similar to the procedure
|
||||||
// for methods above. It is simpler in many respects, especially
|
// for methods above. It is simpler in many respects, especially
|
||||||
// because we shouldn't really have to deal with lifetimes or
|
// because we shouldn't really have to deal with lifetimes or
|
||||||
// predicates. In fact some of this should probably be put into
|
// predicates. In fact some of this should probably be put into
|
||||||
// shared functions because of DRY violations...
|
// shared functions because of DRY violations...
|
||||||
let trait_to_impl_args = impl_trait_ref.args;
|
let impl_args = GenericArgs::identity_for_item(tcx, impl_ct.def_id);
|
||||||
|
let trait_to_impl_args =
|
||||||
|
impl_args.rebase_onto(tcx, impl_ct.container_id(tcx), impl_trait_ref.args);
|
||||||
|
|
||||||
// Create a parameter environment that represents the implementation's
|
// Create a parameter environment that represents the implementation's
|
||||||
// method.
|
// method.
|
||||||
// Compute placeholder form of impl and trait const tys.
|
// Compute placeholder form of impl and trait const tys.
|
||||||
let impl_ty = tcx.type_of(impl_const_item_def.to_def_id()).instantiate_identity();
|
let impl_ty = tcx.type_of(impl_ct_def_id).instantiate_identity();
|
||||||
let trait_ty = tcx.type_of(trait_const_item_def).instantiate(tcx, trait_to_impl_args);
|
|
||||||
let mut cause = ObligationCause::new(
|
let trait_ty = tcx.type_of(trait_ct.def_id).instantiate(tcx, trait_to_impl_args);
|
||||||
impl_c_span,
|
let code = ObligationCauseCode::CompareImplItemObligation {
|
||||||
impl_const_item_def,
|
impl_item_def_id: impl_ct_def_id,
|
||||||
ObligationCauseCode::CompareImplItemObligation {
|
trait_item_def_id: trait_ct.def_id,
|
||||||
impl_item_def_id: impl_const_item_def,
|
kind: impl_ct.kind,
|
||||||
trait_item_def_id: trait_const_item_def,
|
};
|
||||||
kind: impl_const_item.kind,
|
let mut cause = ObligationCause::new(impl_ct_span, impl_ct_def_id, code.clone());
|
||||||
},
|
|
||||||
|
let impl_ct_predicates = tcx.predicates_of(impl_ct.def_id);
|
||||||
|
let trait_ct_predicates = tcx.predicates_of(trait_ct.def_id);
|
||||||
|
|
||||||
|
check_region_bounds_on_impl_item(tcx, impl_ct, trait_ct, false)?;
|
||||||
|
|
||||||
|
// The predicates declared by the impl definition, the trait and the
|
||||||
|
// associated const in the trait are assumed.
|
||||||
|
let impl_predicates = tcx.predicates_of(impl_ct_predicates.parent.unwrap());
|
||||||
|
let mut hybrid_preds = impl_predicates.instantiate_identity(tcx);
|
||||||
|
hybrid_preds.predicates.extend(
|
||||||
|
trait_ct_predicates
|
||||||
|
.instantiate_own(tcx, trait_to_impl_args)
|
||||||
|
.map(|(predicate, _)| predicate),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds.predicates), Reveal::UserFacing);
|
||||||
|
let param_env = traits::normalize_param_env_or_error(
|
||||||
|
tcx,
|
||||||
|
param_env,
|
||||||
|
ObligationCause::misc(impl_ct_span, impl_ct_def_id),
|
||||||
|
);
|
||||||
|
|
||||||
|
let infcx = tcx.infer_ctxt().build();
|
||||||
|
let ocx = ObligationCtxt::new(&infcx);
|
||||||
|
|
||||||
|
let impl_ct_own_bounds = impl_ct_predicates.instantiate_own(tcx, impl_args);
|
||||||
|
for (predicate, span) in impl_ct_own_bounds {
|
||||||
|
let cause = ObligationCause::misc(span, impl_ct_def_id);
|
||||||
|
let predicate = ocx.normalize(&cause, param_env, predicate);
|
||||||
|
|
||||||
|
let cause = ObligationCause::new(span, impl_ct_def_id, code.clone());
|
||||||
|
ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate));
|
||||||
|
}
|
||||||
|
|
||||||
// There is no "body" here, so just pass dummy id.
|
// There is no "body" here, so just pass dummy id.
|
||||||
let impl_ty = ocx.normalize(&cause, param_env, impl_ty);
|
let impl_ty = ocx.normalize(&cause, param_env, impl_ty);
|
||||||
|
|
||||||
|
@ -1817,7 +1861,7 @@ pub(super) fn compare_impl_const_raw(
|
||||||
);
|
);
|
||||||
|
|
||||||
// Locate the Span containing just the type of the offending impl
|
// Locate the Span containing just the type of the offending impl
|
||||||
let (ty, _) = tcx.hir().expect_impl_item(impl_const_item_def).expect_const();
|
let (ty, _) = tcx.hir().expect_impl_item(impl_ct_def_id).expect_const();
|
||||||
cause.span = ty.span;
|
cause.span = ty.span;
|
||||||
|
|
||||||
let mut diag = struct_span_err!(
|
let mut diag = struct_span_err!(
|
||||||
|
@ -1825,12 +1869,12 @@ pub(super) fn compare_impl_const_raw(
|
||||||
cause.span,
|
cause.span,
|
||||||
E0326,
|
E0326,
|
||||||
"implemented const `{}` has an incompatible type for trait",
|
"implemented const `{}` has an incompatible type for trait",
|
||||||
trait_const_item.name
|
trait_ct.name
|
||||||
);
|
);
|
||||||
|
|
||||||
let trait_c_span = trait_const_item_def.as_local().map(|trait_c_def_id| {
|
let trait_c_span = trait_ct.def_id.as_local().map(|trait_ct_def_id| {
|
||||||
// Add a label to the Span containing just the type of the const
|
// Add a label to the Span containing just the type of the const
|
||||||
let (ty, _) = tcx.hir().expect_trait_item(trait_c_def_id).expect_const();
|
let (ty, _) = tcx.hir().expect_trait_item(trait_ct_def_id).expect_const();
|
||||||
ty.span
|
ty.span
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1857,7 +1901,7 @@ pub(super) fn compare_impl_const_raw(
|
||||||
}
|
}
|
||||||
|
|
||||||
let outlives_env = OutlivesEnvironment::new(param_env);
|
let outlives_env = OutlivesEnvironment::new(param_env);
|
||||||
ocx.resolve_regions_and_report_errors(impl_const_item_def, &outlives_env)
|
ocx.resolve_regions_and_report_errors(impl_ct_def_id, &outlives_env)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn compare_impl_ty<'tcx>(
|
pub(super) fn compare_impl_ty<'tcx>(
|
||||||
|
@ -1899,7 +1943,7 @@ fn compare_type_predicate_entailment<'tcx>(
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// This `HirId` should be used for the `body_id` field on each
|
// This `DefId` should be used for the `body_id` field on each
|
||||||
// `ObligationCause` (and the `FnCtxt`). This is what
|
// `ObligationCause` (and the `FnCtxt`). This is what
|
||||||
// `regionck_item` expects.
|
// `regionck_item` expects.
|
||||||
let impl_ty_def_id = impl_ty.def_id.expect_local();
|
let impl_ty_def_id = impl_ty.def_id.expect_local();
|
||||||
|
@ -1918,7 +1962,7 @@ fn compare_type_predicate_entailment<'tcx>(
|
||||||
debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds);
|
debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds);
|
||||||
|
|
||||||
let impl_ty_span = tcx.def_span(impl_ty_def_id);
|
let impl_ty_span = tcx.def_span(impl_ty_def_id);
|
||||||
let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_def_id);
|
let normalize_cause = ObligationCause::misc(impl_ty_span, impl_ty_def_id);
|
||||||
let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds.predicates), Reveal::UserFacing);
|
let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds.predicates), Reveal::UserFacing);
|
||||||
let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
|
let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
|
||||||
let infcx = tcx.infer_ctxt().build();
|
let infcx = tcx.infer_ctxt().build();
|
||||||
|
@ -1963,7 +2007,7 @@ fn compare_type_predicate_entailment<'tcx>(
|
||||||
///
|
///
|
||||||
/// trait X { type Y: Copy } impl X for T { type Y = S; }
|
/// trait X { type Y: Copy } impl X for T { type Y = S; }
|
||||||
///
|
///
|
||||||
/// We are able to normalize `<T as X>::U` to `S`, and so when we check the
|
/// We are able to normalize `<T as X>::Y` to `S`, and so when we check the
|
||||||
/// impl is well-formed we have to prove `S: Copy`.
|
/// impl is well-formed we have to prove `S: Copy`.
|
||||||
///
|
///
|
||||||
/// For default associated types the normalization is not possible (the value
|
/// For default associated types the normalization is not possible (the value
|
||||||
|
|
|
@ -209,6 +209,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
||||||
| ItemKind::Struct(..)
|
| ItemKind::Struct(..)
|
||||||
| ItemKind::OpaqueTy(..)
|
| ItemKind::OpaqueTy(..)
|
||||||
| ItemKind::Union(..) => (None, Defaults::Allowed),
|
| ItemKind::Union(..) => (None, Defaults::Allowed),
|
||||||
|
ItemKind::Const(..) => (None, Defaults::Deny),
|
||||||
_ => (None, Defaults::FutureCompatDisallowed),
|
_ => (None, Defaults::FutureCompatDisallowed),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -156,6 +156,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
||||||
}
|
}
|
||||||
ItemKind::Fn(.., generics, _)
|
ItemKind::Fn(.., generics, _)
|
||||||
| ItemKind::TyAlias(_, generics)
|
| ItemKind::TyAlias(_, generics)
|
||||||
|
| ItemKind::Const(_, generics, _)
|
||||||
| ItemKind::Enum(_, generics)
|
| ItemKind::Enum(_, generics)
|
||||||
| ItemKind::Struct(_, generics)
|
| ItemKind::Struct(_, generics)
|
||||||
| ItemKind::Union(_, generics) => generics,
|
| ItemKind::Union(_, generics) => generics,
|
||||||
|
@ -762,6 +763,7 @@ pub(super) fn type_param_predicates(
|
||||||
ItemKind::Fn(.., generics, _)
|
ItemKind::Fn(.., generics, _)
|
||||||
| ItemKind::Impl(&hir::Impl { generics, .. })
|
| ItemKind::Impl(&hir::Impl { generics, .. })
|
||||||
| ItemKind::TyAlias(_, generics)
|
| ItemKind::TyAlias(_, generics)
|
||||||
|
| ItemKind::Const(_, generics, _)
|
||||||
| ItemKind::OpaqueTy(&OpaqueTy {
|
| ItemKind::OpaqueTy(&OpaqueTy {
|
||||||
generics,
|
generics,
|
||||||
origin: hir::OpaqueTyOrigin::TyAlias { .. },
|
origin: hir::OpaqueTyOrigin::TyAlias { .. },
|
||||||
|
|
|
@ -518,7 +518,6 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
||||||
| hir::ItemKind::Mod(..)
|
| hir::ItemKind::Mod(..)
|
||||||
| hir::ItemKind::ForeignMod { .. }
|
| hir::ItemKind::ForeignMod { .. }
|
||||||
| hir::ItemKind::Static(..)
|
| hir::ItemKind::Static(..)
|
||||||
| hir::ItemKind::Const(..)
|
|
||||||
| hir::ItemKind::GlobalAsm(..) => {
|
| hir::ItemKind::GlobalAsm(..) => {
|
||||||
// These sorts of items have no lifetime parameters at all.
|
// These sorts of items have no lifetime parameters at all.
|
||||||
intravisit::walk_item(self, item);
|
intravisit::walk_item(self, item);
|
||||||
|
@ -583,6 +582,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
hir::ItemKind::TyAlias(_, generics)
|
hir::ItemKind::TyAlias(_, generics)
|
||||||
|
| hir::ItemKind::Const(_, generics, _)
|
||||||
| hir::ItemKind::Enum(_, generics)
|
| hir::ItemKind::Enum(_, generics)
|
||||||
| hir::ItemKind::Struct(_, generics)
|
| hir::ItemKind::Struct(_, generics)
|
||||||
| hir::ItemKind::Union(_, generics)
|
| hir::ItemKind::Union(_, generics)
|
||||||
|
@ -590,21 +590,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
||||||
| hir::ItemKind::TraitAlias(generics, ..)
|
| hir::ItemKind::TraitAlias(generics, ..)
|
||||||
| hir::ItemKind::Impl(&hir::Impl { generics, .. }) => {
|
| hir::ItemKind::Impl(&hir::Impl { generics, .. }) => {
|
||||||
// These kinds of items have only early-bound lifetime parameters.
|
// These kinds of items have only early-bound lifetime parameters.
|
||||||
let bound_vars = generics.params.iter().map(ResolvedArg::early).collect();
|
self.visit_early(item.hir_id(), generics, |this| intravisit::walk_item(this, item));
|
||||||
self.record_late_bound_vars(item.hir_id(), vec![]);
|
|
||||||
let scope = Scope::Binder {
|
|
||||||
hir_id: item.hir_id(),
|
|
||||||
bound_vars,
|
|
||||||
scope_type: BinderScopeType::Normal,
|
|
||||||
s: self.scope,
|
|
||||||
where_bound_origin: None,
|
|
||||||
};
|
|
||||||
self.with(scope, |this| {
|
|
||||||
let scope = Scope::TraitRefBoundary { s: this.scope };
|
|
||||||
this.with(scope, |this| {
|
|
||||||
intravisit::walk_item(this, item);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -777,39 +763,24 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
||||||
use self::hir::TraitItemKind::*;
|
use self::hir::TraitItemKind::*;
|
||||||
match trait_item.kind {
|
match trait_item.kind {
|
||||||
Fn(_, _) => {
|
Fn(_, _) => {
|
||||||
self.visit_early_late(trait_item.hir_id(), &trait_item.generics, |this| {
|
self.visit_early_late(trait_item.hir_id(), trait_item.generics, |this| {
|
||||||
intravisit::walk_trait_item(this, trait_item)
|
intravisit::walk_trait_item(this, trait_item)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Type(bounds, ty) => {
|
Type(bounds, ty) => {
|
||||||
let generics = &trait_item.generics;
|
self.visit_early(trait_item.hir_id(), trait_item.generics, |this| {
|
||||||
let bound_vars = generics.params.iter().map(ResolvedArg::early).collect();
|
this.visit_generics(&trait_item.generics);
|
||||||
self.record_late_bound_vars(trait_item.hir_id(), vec![]);
|
for bound in bounds {
|
||||||
let scope = Scope::Binder {
|
this.visit_param_bound(bound);
|
||||||
hir_id: trait_item.hir_id(),
|
}
|
||||||
bound_vars,
|
if let Some(ty) = ty {
|
||||||
s: self.scope,
|
this.visit_ty(ty);
|
||||||
scope_type: BinderScopeType::Normal,
|
}
|
||||||
where_bound_origin: None,
|
})
|
||||||
};
|
|
||||||
self.with(scope, |this| {
|
|
||||||
let scope = Scope::TraitRefBoundary { s: this.scope };
|
|
||||||
this.with(scope, |this| {
|
|
||||||
this.visit_generics(generics);
|
|
||||||
for bound in bounds {
|
|
||||||
this.visit_param_bound(bound);
|
|
||||||
}
|
|
||||||
if let Some(ty) = ty {
|
|
||||||
this.visit_ty(ty);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Const(_, _) => {
|
|
||||||
// Only methods and types support generics.
|
|
||||||
assert!(trait_item.generics.params.is_empty());
|
|
||||||
intravisit::walk_trait_item(self, trait_item);
|
|
||||||
}
|
}
|
||||||
|
Const(_, _) => self.visit_early(trait_item.hir_id(), trait_item.generics, |this| {
|
||||||
|
intravisit::walk_trait_item(this, trait_item)
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -817,34 +788,16 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
||||||
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
|
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
|
||||||
use self::hir::ImplItemKind::*;
|
use self::hir::ImplItemKind::*;
|
||||||
match impl_item.kind {
|
match impl_item.kind {
|
||||||
Fn(..) => self.visit_early_late(impl_item.hir_id(), &impl_item.generics, |this| {
|
Fn(..) => self.visit_early_late(impl_item.hir_id(), impl_item.generics, |this| {
|
||||||
|
intravisit::walk_impl_item(this, impl_item)
|
||||||
|
}),
|
||||||
|
Type(ty) => self.visit_early(impl_item.hir_id(), impl_item.generics, |this| {
|
||||||
|
this.visit_generics(impl_item.generics);
|
||||||
|
this.visit_ty(ty);
|
||||||
|
}),
|
||||||
|
Const(_, _) => self.visit_early(impl_item.hir_id(), impl_item.generics, |this| {
|
||||||
intravisit::walk_impl_item(this, impl_item)
|
intravisit::walk_impl_item(this, impl_item)
|
||||||
}),
|
}),
|
||||||
Type(ty) => {
|
|
||||||
let generics = &impl_item.generics;
|
|
||||||
let bound_vars: FxIndexMap<LocalDefId, ResolvedArg> =
|
|
||||||
generics.params.iter().map(ResolvedArg::early).collect();
|
|
||||||
self.record_late_bound_vars(impl_item.hir_id(), vec![]);
|
|
||||||
let scope = Scope::Binder {
|
|
||||||
hir_id: impl_item.hir_id(),
|
|
||||||
bound_vars,
|
|
||||||
s: self.scope,
|
|
||||||
scope_type: BinderScopeType::Normal,
|
|
||||||
where_bound_origin: None,
|
|
||||||
};
|
|
||||||
self.with(scope, |this| {
|
|
||||||
let scope = Scope::TraitRefBoundary { s: this.scope };
|
|
||||||
this.with(scope, |this| {
|
|
||||||
this.visit_generics(generics);
|
|
||||||
this.visit_ty(ty);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Const(_, _) => {
|
|
||||||
// Only methods and types support generics.
|
|
||||||
assert!(impl_item.generics.params.is_empty());
|
|
||||||
intravisit::walk_impl_item(self, impl_item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1180,6 +1133,25 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
||||||
self.with(scope, walk);
|
self.with(scope, walk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_early<F>(&mut self, hir_id: hir::HirId, generics: &'tcx hir::Generics<'tcx>, walk: F)
|
||||||
|
where
|
||||||
|
F: for<'b, 'c> FnOnce(&'b mut BoundVarContext<'c, 'tcx>),
|
||||||
|
{
|
||||||
|
let bound_vars = generics.params.iter().map(ResolvedArg::early).collect();
|
||||||
|
self.record_late_bound_vars(hir_id, vec![]);
|
||||||
|
let scope = Scope::Binder {
|
||||||
|
hir_id,
|
||||||
|
bound_vars,
|
||||||
|
s: self.scope,
|
||||||
|
scope_type: BinderScopeType::Normal,
|
||||||
|
where_bound_origin: None,
|
||||||
|
};
|
||||||
|
self.with(scope, |this| {
|
||||||
|
let scope = Scope::TraitRefBoundary { s: this.scope };
|
||||||
|
this.with(scope, walk)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(self))]
|
#[instrument(level = "debug", skip(self))]
|
||||||
fn resolve_lifetime_ref(
|
fn resolve_lifetime_ref(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue