mod errors;
mod generics;
use crate::bounds::Bounds;
use crate::collect::PlaceholderHirTyCollector;
use crate::errors::{
AmbiguousLifetimeBound, MultipleRelaxedDefaultBounds, TraitObjectDeclaredWithNoTraits,
TypeofReservedKeywordUsed, ValueOfAssociatedStructAlreadySpecified,
};
use crate::middle::resolve_lifetime as rl;
use crate::require_c_abi_if_c_variadic;
use rustc_ast::util::lev_distance::find_best_match_for_name;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{struct_span_err, Applicability, ErrorReported, FatalError};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{walk_generics, Visitor as _};
use rustc_hir::lang_items::LangItem;
use rustc_hir::{Constness, GenericArg, GenericArgs};
use rustc_middle::ty::subst::{self, InternalSubsts, Subst, SubstsRef};
use rustc_middle::ty::GenericParamDefKind;
use rustc_middle::ty::{self, Const, DefIdTree, Ty, TyCtxt, TypeFoldable};
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
use rustc_span::symbol::{Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
use rustc_target::spec::abi;
use rustc_trait_selection::traits;
use rustc_trait_selection::traits::astconv_object_safety_violations;
use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
use rustc_trait_selection::traits::wf::object_region_bounds;
use smallvec::SmallVec;
use std::array;
use std::collections::BTreeSet;
use std::slice;
#[derive(Debug)]
pub struct PathSeg(pub DefId, pub usize);
pub trait AstConv<'tcx> {
fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
fn item_def_id(&self) -> Option<DefId>;
fn default_constness_for_trait_bounds(&self) -> Constness;
fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) -> ty::GenericPredicates<'tcx>;
fn re_infer(&self, param: Option<&ty::GenericParamDef>, span: Span)
-> Option<ty::Region<'tcx>>;
fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx>;
fn allow_ty_infer(&self) -> bool;
fn ct_infer(
&self,
ty: Ty<'tcx>,
param: Option<&ty::GenericParamDef>,
span: Span,
) -> &'tcx Const<'tcx>;
fn projected_ty_from_poly_trait_ref(
&self,
span: Span,
item_def_id: DefId,
item_segment: &hir::PathSegment<'_>,
poly_trait_ref: ty::PolyTraitRef<'tcx>,
) -> Ty<'tcx>;
fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx>;
fn set_tainted_by_errors(&self);
fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span);
}
pub enum SizedByDefault {
Yes,
No,
}
struct ConvertedBinding<'a, 'tcx> {
item_name: Ident,
kind: ConvertedBindingKind<'a, 'tcx>,
span: Span,
}
enum ConvertedBindingKind<'a, 'tcx> {
Equality(Ty<'tcx>),
Constraint(&'a [hir::GenericBound<'a>]),
}
#[derive(Copy, Clone, PartialEq)]
pub enum ExplicitLateBound {
Yes,
No,
}
#[derive(Copy, Clone, PartialEq)]
pub(crate) enum GenericArgPosition {
Type,
Value,
MethodCall,
}
#[derive(Clone, Default)]
pub struct GenericArgCountMismatch {
pub reported: Option<ErrorReported>,
pub invalid_args: Vec<Span>,
}
#[derive(Clone)]
pub struct GenericArgCountResult {
pub explicit_late_bound: ExplicitLateBound,
pub correct: Result<(), GenericArgCountMismatch>,
}
pub trait CreateSubstsForGenericArgsCtxt<'a, 'tcx> {
fn args_for_def_id(&mut self, def_id: DefId) -> (Option<&'a GenericArgs<'a>>, bool);
fn provided_kind(
&mut self,
param: &ty::GenericParamDef,
arg: &GenericArg<'_>,
) -> subst::GenericArg<'tcx>;
fn inferred_kind(
&mut self,
substs: Option<&[subst::GenericArg<'tcx>]>,
param: &ty::GenericParamDef,
infer_args: bool,
) -> subst::GenericArg<'tcx>;
}
impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
pub fn ast_region_to_region(
&self,
lifetime: &hir::Lifetime,
def: Option<&ty::GenericParamDef>,
) -> ty::Region<'tcx> {
let tcx = self.tcx();
let lifetime_name = |def_id| tcx.hir().name(tcx.hir().local_def_id_to_hir_id(def_id));
let r = match tcx.named_region(lifetime.hir_id) {
Some(rl::Region::Static) => tcx.lifetimes.re_static,
Some(rl::Region::LateBound(debruijn, id, _)) => {
let name = lifetime_name(id.expect_local());
tcx.mk_region(ty::ReLateBound(debruijn, ty::BrNamed(id, name)))
}
Some(rl::Region::LateBoundAnon(debruijn, index)) => {
tcx.mk_region(ty::ReLateBound(debruijn, ty::BrAnon(index)))
}
Some(rl::Region::EarlyBound(index, id, _)) => {
let name = lifetime_name(id.expect_local());
tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { def_id: id, index, name }))
}
Some(rl::Region::Free(scope, id)) => {
let name = lifetime_name(id.expect_local());
tcx.mk_region(ty::ReFree(ty::FreeRegion {
scope,
bound_region: ty::BrNamed(id, name),
}))
}
None => {
self.re_infer(def, lifetime.span).unwrap_or_else(|| {
tcx.sess.delay_span_bug(lifetime.span, "unelided lifetime in signature");
tcx.lifetimes.re_static
})
}
};
debug!("ast_region_to_region(lifetime={:?}) yields {:?}", lifetime, r);
r
}
pub fn ast_path_substs_for_ty(
&self,
span: Span,
def_id: DefId,
item_segment: &hir::PathSegment<'_>,
) -> SubstsRef<'tcx> {
let (substs, assoc_bindings, _) = self.create_substs_for_ast_path(
span,
def_id,
&[],
item_segment.generic_args(),
item_segment.infer_args,
None,
);
if let Some(b) = assoc_bindings.first() {
Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
}
substs
}
fn create_substs_for_ast_path<'a>(
&self,
span: Span,
def_id: DefId,
parent_substs: &[subst::GenericArg<'tcx>],
generic_args: &'a hir::GenericArgs<'_>,
infer_args: bool,
self_ty: Option<Ty<'tcx>>,
) -> (SubstsRef<'tcx>, Vec<ConvertedBinding<'a, 'tcx>>, GenericArgCountResult) {
debug!(
"create_substs_for_ast_path(def_id={:?}, self_ty={:?}, \
generic_args={:?})",
def_id, self_ty, generic_args
);
let tcx = self.tcx();
let generic_params = tcx.generics_of(def_id);
if generic_params.has_self {
if generic_params.parent.is_some() {
assert!(!parent_substs.is_empty())
} else {
assert!(self_ty.is_some());
}
} else {
assert!(self_ty.is_none() && parent_substs.is_empty());
}
let arg_count = Self::check_generic_arg_count(
tcx,
span,
&generic_params,
&generic_args,
GenericArgPosition::Type,
self_ty.is_some(),
infer_args,
);
let is_object = self_ty.map_or(false, |ty| ty == self.tcx().types.trait_object_dummy_self);
struct SubstsForAstPathCtxt<'a, 'tcx> {
astconv: &'a (dyn AstConv<'tcx> + 'a),
def_id: DefId,
generic_args: &'a GenericArgs<'a>,
span: Span,
missing_type_params: Vec<String>,
inferred_params: Vec<Span>,
infer_args: bool,
is_object: bool,
}
impl<'tcx, 'a> SubstsForAstPathCtxt<'tcx, 'a> {
fn default_needs_object_self(&mut self, param: &ty::GenericParamDef) -> bool {
let tcx = self.astconv.tcx();
if let GenericParamDefKind::Type { has_default, .. } = param.kind {
if self.is_object && has_default {
let default_ty = tcx.at(self.span).type_of(param.def_id);
let self_param = tcx.types.self_param;
if default_ty.walk().any(|arg| arg == self_param.into()) {
return true;
}
}
}
false
}
}
impl<'a, 'tcx> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for SubstsForAstPathCtxt<'a, 'tcx> {
fn args_for_def_id(&mut self, did: DefId) -> (Option<&'a GenericArgs<'a>>, bool) {
if did == self.def_id {
(Some(self.generic_args), self.infer_args)
} else {
(None, false)
}
}
fn provided_kind(
&mut self,
param: &ty::GenericParamDef,
arg: &GenericArg<'_>,
) -> subst::GenericArg<'tcx> {
let tcx = self.astconv.tcx();
match (¶m.kind, arg) {
(GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
self.astconv.ast_region_to_region(<, Some(param)).into()
}
(&GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => {
if has_default {
tcx.check_optional_stability(
param.def_id,
Some(arg.id()),
arg.span(),
|_, _| {
},
)
}
if let (hir::TyKind::Infer, false) =
(&ty.kind, self.astconv.allow_ty_infer())
{
self.inferred_params.push(ty.span);
tcx.ty_error().into()
} else {
self.astconv.ast_ty_to_ty(&ty).into()
}
}
(GenericParamDefKind::Const, GenericArg::Const(ct)) => {
ty::Const::from_opt_const_arg_anon_const(
tcx,
ty::WithOptConstParam {
did: tcx.hir().local_def_id(ct.value.hir_id),
const_param_did: Some(param.def_id),
},
)
.into()
}
_ => unreachable!(),
}
}
fn inferred_kind(
&mut self,
substs: Option<&[subst::GenericArg<'tcx>]>,
param: &ty::GenericParamDef,
infer_args: bool,
) -> subst::GenericArg<'tcx> {
let tcx = self.astconv.tcx();
match param.kind {
GenericParamDefKind::Lifetime => tcx.lifetimes.re_static.into(),
GenericParamDefKind::Type { has_default, .. } => {
if !infer_args && has_default {
if self.default_needs_object_self(param) {
self.missing_type_params.push(param.name.to_string());
tcx.ty_error().into()
} else {
self.astconv
.normalize_ty(
self.span,
tcx.at(self.span).type_of(param.def_id).subst_spanned(
tcx,
substs.unwrap(),
Some(self.span),
),
)
.into()
}
} else if infer_args {
let param = if !self.default_needs_object_self(param) {
Some(param)
} else {
None
};
self.astconv.ty_infer(param, self.span).into()
} else {
tcx.ty_error().into()
}
}
GenericParamDefKind::Const => {
let ty = tcx.at(self.span).type_of(param.def_id);
if infer_args {
self.astconv.ct_infer(ty, Some(param), self.span).into()
} else {
tcx.const_error(ty).into()
}
}
}
}
}
let mut substs_ctx = SubstsForAstPathCtxt {
astconv: self,
def_id,
span,
generic_args,
missing_type_params: vec![],
inferred_params: vec![],
infer_args,
is_object,
};
let substs = Self::create_substs_for_generic_args(
tcx,
def_id,
parent_substs,
self_ty.is_some(),
self_ty,
arg_count.clone(),
&mut substs_ctx,
);
self.complain_about_missing_type_params(
substs_ctx.missing_type_params,
def_id,
span,
generic_args.args.is_empty(),
);
let assoc_bindings = generic_args
.bindings
.iter()
.map(|binding| {
let kind = match binding.kind {
hir::TypeBindingKind::Equality { ref ty } => {
ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty))
}
hir::TypeBindingKind::Constraint { ref bounds } => {
ConvertedBindingKind::Constraint(bounds)
}
};
ConvertedBinding { item_name: binding.ident, kind, span: binding.span }
})
.collect();
debug!(
"create_substs_for_ast_path(generic_params={:?}, self_ty={:?}) -> {:?}",
generic_params, self_ty, substs
);
(substs, assoc_bindings, arg_count)
}
crate fn create_substs_for_associated_item(
&self,
tcx: TyCtxt<'tcx>,
span: Span,
item_def_id: DefId,
item_segment: &hir::PathSegment<'_>,
parent_substs: SubstsRef<'tcx>,
) -> SubstsRef<'tcx> {
if tcx.generics_of(item_def_id).params.is_empty() {
self.prohibit_generics(slice::from_ref(item_segment));
parent_substs
} else {
self.create_substs_for_ast_path(
span,
item_def_id,
parent_substs,
item_segment.generic_args(),
item_segment.infer_args,
None,
)
.0
}
}
pub fn instantiate_mono_trait_ref(
&self,
trait_ref: &hir::TraitRef<'_>,
self_ty: Ty<'tcx>,
) -> ty::TraitRef<'tcx> {
self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1);
self.ast_path_to_mono_trait_ref(
trait_ref.path.span,
trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()),
self_ty,
trait_ref.path.segments.last().unwrap(),
)
}
pub(super) fn instantiate_poly_trait_ref_inner(
&self,
trait_ref: &hir::TraitRef<'_>,
span: Span,
constness: Constness,
self_ty: Ty<'tcx>,
bounds: &mut Bounds<'tcx>,
speculative: bool,
) -> GenericArgCountResult {
let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise());
debug!("instantiate_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id);
self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1);
let (substs, assoc_bindings, arg_count) = self.create_substs_for_ast_trait_ref(
trait_ref.path.span,
trait_def_id,
self_ty,
trait_ref.path.segments.last().unwrap(),
);
let poly_trait_ref = ty::Binder::bind(ty::TraitRef::new(trait_def_id, substs));
bounds.trait_bounds.push((poly_trait_ref, span, constness));
let mut dup_bindings = FxHashMap::default();
for binding in &assoc_bindings {
let _: Result<_, ErrorReported> = self.add_predicates_for_ast_type_binding(
trait_ref.hir_ref_id,
poly_trait_ref,
binding,
bounds,
speculative,
&mut dup_bindings,
binding.span,
);
}
debug!(
"instantiate_poly_trait_ref({:?}, bounds={:?}) -> {:?}",
trait_ref, bounds, poly_trait_ref
);
arg_count
}
pub fn instantiate_poly_trait_ref(
&self,
poly_trait_ref: &hir::PolyTraitRef<'_>,
constness: Constness,
self_ty: Ty<'tcx>,
bounds: &mut Bounds<'tcx>,
) -> GenericArgCountResult {
self.instantiate_poly_trait_ref_inner(
&poly_trait_ref.trait_ref,
poly_trait_ref.span,
constness,
self_ty,
bounds,
false,
)
}
pub fn instantiate_lang_item_trait_ref(
&self,
lang_item: hir::LangItem,
span: Span,
hir_id: hir::HirId,
args: &GenericArgs<'_>,
self_ty: Ty<'tcx>,
bounds: &mut Bounds<'tcx>,
) {
let trait_def_id = self.tcx().require_lang_item(lang_item, Some(span));
let (substs, assoc_bindings, _) =
self.create_substs_for_ast_path(span, trait_def_id, &[], args, false, Some(self_ty));
let poly_trait_ref = ty::Binder::bind(ty::TraitRef::new(trait_def_id, substs));
bounds.trait_bounds.push((poly_trait_ref, span, Constness::NotConst));
let mut dup_bindings = FxHashMap::default();
for binding in assoc_bindings {
let _: Result<_, ErrorReported> = self.add_predicates_for_ast_type_binding(
hir_id,
poly_trait_ref,
&binding,
bounds,
false,
&mut dup_bindings,
span,
);
}
}
fn ast_path_to_mono_trait_ref(
&self,
span: Span,
trait_def_id: DefId,
self_ty: Ty<'tcx>,
trait_segment: &hir::PathSegment<'_>,
) -> ty::TraitRef<'tcx> {
let (substs, assoc_bindings, _) =
self.create_substs_for_ast_trait_ref(span, trait_def_id, self_ty, trait_segment);
if let Some(b) = assoc_bindings.first() {
Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
}
ty::TraitRef::new(trait_def_id, substs)
}
fn create_substs_for_ast_trait_ref<'a>(
&self,
span: Span,
trait_def_id: DefId,
self_ty: Ty<'tcx>,
trait_segment: &'a hir::PathSegment<'a>,
) -> (SubstsRef<'tcx>, Vec<ConvertedBinding<'a, 'tcx>>, GenericArgCountResult) {
debug!("create_substs_for_ast_trait_ref(trait_segment={:?})", trait_segment);
self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment);
self.create_substs_for_ast_path(
span,
trait_def_id,
&[],
trait_segment.generic_args(),
trait_segment.infer_args,
Some(self_ty),
)
}
fn trait_defines_associated_type_named(&self, trait_def_id: DefId, assoc_name: Ident) -> bool {
self.tcx()
.associated_items(trait_def_id)
.find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Type, trait_def_id)
.is_some()
}
pub fn is_unsized(&self, ast_bounds: &[hir::GenericBound<'_>], span: Span) -> bool {
let tcx = self.tcx();
let mut unbound = None;
for ab in ast_bounds {
if let &hir::GenericBound::Trait(ref ptr, hir::TraitBoundModifier::Maybe) = ab {
if unbound.is_none() {
unbound = Some(&ptr.trait_ref);
} else {
tcx.sess.emit_err(MultipleRelaxedDefaultBounds { span });
}
}
}
let kind_id = tcx.lang_items().require(LangItem::Sized);
match unbound {
Some(tpb) => {
if let Ok(kind_id) = kind_id {
if tpb.path.res != Res::Def(DefKind::Trait, kind_id) {
tcx.sess.span_warn(
span,
"default bound relaxed for a type parameter, but \
this does nothing because the given bound is not \
a default; only `?Sized` is supported",
);
}
}
}
_ if kind_id.is_ok() => {
return false;
}
None => {}
}
true
}
fn add_bounds(
&self,
param_ty: Ty<'tcx>,
ast_bounds: &[hir::GenericBound<'_>],
bounds: &mut Bounds<'tcx>,
) {
let mut trait_bounds = Vec::new();
let mut region_bounds = Vec::new();
let constness = self.default_constness_for_trait_bounds();
for ast_bound in ast_bounds {
match *ast_bound {
hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::None) => {
trait_bounds.push((b, constness))
}
hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::MaybeConst) => {
trait_bounds.push((b, Constness::NotConst))
}
hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {}
hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => self
.instantiate_lang_item_trait_ref(
lang_item, span, hir_id, args, param_ty, bounds,
),
hir::GenericBound::Outlives(ref l) => region_bounds.push(l),
}
}
for (bound, constness) in trait_bounds {
let _ = self.instantiate_poly_trait_ref(bound, constness, param_ty, bounds);
}
bounds.region_bounds.extend(
region_bounds.into_iter().map(|r| (self.ast_region_to_region(r, None), r.span)),
);
}
pub fn compute_bounds(
&self,
param_ty: Ty<'tcx>,
ast_bounds: &[hir::GenericBound<'_>],
sized_by_default: SizedByDefault,
span: Span,
) -> Bounds<'tcx> {
let mut bounds = Bounds::default();
self.add_bounds(param_ty, ast_bounds, &mut bounds);
bounds.trait_bounds.sort_by_key(|(t, _, _)| t.def_id());
bounds.implicitly_sized = if let SizedByDefault::Yes = sized_by_default {
if !self.is_unsized(ast_bounds, span) { Some(span) } else { None }
} else {
None
};
bounds
}
fn add_predicates_for_ast_type_binding(
&self,
hir_ref_id: hir::HirId,
trait_ref: ty::PolyTraitRef<'tcx>,
binding: &ConvertedBinding<'_, 'tcx>,
bounds: &mut Bounds<'tcx>,
speculative: bool,
dup_bindings: &mut FxHashMap<DefId, Span>,
path_span: Span,
) -> Result<(), ErrorReported> {
let tcx = self.tcx();
if !speculative {
if let ConvertedBindingKind::Equality(ty) = binding.kind {
let late_bound_in_trait_ref =
tcx.collect_constrained_late_bound_regions(&trait_ref);
let late_bound_in_ty =
tcx.collect_referenced_late_bound_regions(&ty::Binder::bind(ty));
debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref);
debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
self.validate_late_bound_regions(
late_bound_in_trait_ref,
late_bound_in_ty,
|br_name| {
struct_span_err!(
tcx.sess,
binding.span,
E0582,
"binding for associated type `{}` references {}, \
which does not appear in the trait input types",
binding.item_name,
br_name
)
},
);
}
}
let candidate =
if self.trait_defines_associated_type_named(trait_ref.def_id(), binding.item_name) {
trait_ref
} else {
self.one_bound_for_assoc_type(
|| traits::supertraits(tcx, trait_ref),
|| trait_ref.print_only_trait_path().to_string(),
binding.item_name,
path_span,
|| match binding.kind {
ConvertedBindingKind::Equality(ty) => Some(ty.to_string()),
_ => None,
},
)?
};
let (assoc_ident, def_scope) =
tcx.adjust_ident_and_get_scope(binding.item_name, candidate.def_id(), hir_ref_id);
let assoc_ty = tcx
.associated_items(candidate.def_id())
.filter_by_name_unhygienic(assoc_ident.name)
.find(|i| {
i.kind == ty::AssocKind::Type && i.ident.normalize_to_macros_2_0() == assoc_ident
})
.expect("missing associated type");
if !assoc_ty.vis.is_accessible_from(def_scope, tcx) {
tcx.sess
.struct_span_err(
binding.span,
&format!("associated type `{}` is private", binding.item_name),
)
.span_label(binding.span, "private associated type")
.emit();
}
tcx.check_stability(assoc_ty.def_id, Some(hir_ref_id), binding.span);
if !speculative {
dup_bindings
.entry(assoc_ty.def_id)
.and_modify(|prev_span| {
self.tcx().sess.emit_err(ValueOfAssociatedStructAlreadySpecified {
span: binding.span,
prev_span: *prev_span,
item_name: binding.item_name,
def_path: tcx.def_path_str(assoc_ty.container.id()),
});
})
.or_insert(binding.span);
}
match binding.kind {
ConvertedBindingKind::Equality(ref ty) => {
bounds.projection_bounds.push((
candidate.map_bound(|trait_ref| ty::ProjectionPredicate {
projection_ty: ty::ProjectionTy::from_ref_and_name(
tcx,
trait_ref,
binding.item_name,
),
ty,
}),
binding.span,
));
}
ConvertedBindingKind::Constraint(ast_bounds) => {
let param_ty = tcx.mk_projection(assoc_ty.def_id, candidate.skip_binder().substs);
self.add_bounds(param_ty, ast_bounds, bounds);
}
}
Ok(())
}
fn ast_path_to_ty(
&self,
span: Span,
did: DefId,
item_segment: &hir::PathSegment<'_>,
) -> Ty<'tcx> {
let substs = self.ast_path_substs_for_ty(span, did, item_segment);
self.normalize_ty(span, self.tcx().at(span).type_of(did).subst(self.tcx(), substs))
}
fn conv_object_ty_poly_trait_ref(
&self,
span: Span,
trait_bounds: &[hir::PolyTraitRef<'_>],
lifetime: &hir::Lifetime,
borrowed: bool,
) -> Ty<'tcx> {
let tcx = self.tcx();
let mut bounds = Bounds::default();
let mut potential_assoc_types = Vec::new();
let dummy_self = self.tcx().types.trait_object_dummy_self;
for trait_bound in trait_bounds.iter().rev() {
if let GenericArgCountResult {
correct:
Err(GenericArgCountMismatch { invalid_args: cur_potential_assoc_types, .. }),
..
} = self.instantiate_poly_trait_ref(
trait_bound,
Constness::NotConst,
dummy_self,
&mut bounds,
) {
potential_assoc_types.extend(cur_potential_assoc_types.into_iter());
}
}
let expanded_traits =
traits::expand_trait_aliases(tcx, bounds.trait_bounds.iter().map(|&(a, b, _)| (a, b)));
let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) =
expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
if regular_traits.len() > 1 {
let first_trait = ®ular_traits[0];
let additional_trait = ®ular_traits[1];
let mut err = struct_span_err!(
tcx.sess,
additional_trait.bottom().1,
E0225,
"only auto traits can be used as additional traits in a trait object"
);
additional_trait.label_with_exp_info(
&mut err,
"additional non-auto trait",
"additional use",
);
first_trait.label_with_exp_info(&mut err, "first non-auto trait", "first use");
err.help(&format!(
"consider creating a new trait with all of these as super-traits and using that \
trait here instead: `trait NewTrait: {} {{}}`",
regular_traits
.iter()
.map(|t| t.trait_ref().print_only_trait_path().to_string())
.collect::<Vec<_>>()
.join(" + "),
));
err.note(
"auto-traits like `Send` and `Sync` are traits that have special properties; \
for more information on them, visit \
<https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>",
);
err.emit();
}
if regular_traits.is_empty() && auto_traits.is_empty() {
tcx.sess.emit_err(TraitObjectDeclaredWithNoTraits { span });
return tcx.ty_error();
}
for item in ®ular_traits {
let object_safety_violations =
astconv_object_safety_violations(tcx, item.trait_ref().def_id());
if !object_safety_violations.is_empty() {
report_object_safety_error(
tcx,
span,
item.trait_ref().def_id(),
&object_safety_violations[..],
)
.emit();
return tcx.ty_error();
}
}
let mut associated_types: FxHashMap<Span, BTreeSet<DefId>> = FxHashMap::default();
let regular_traits_refs_spans = bounds
.trait_bounds
.into_iter()
.filter(|(trait_ref, _, _)| !tcx.trait_is_auto(trait_ref.def_id()));
for (base_trait_ref, span, constness) in regular_traits_refs_spans {
assert_eq!(constness, Constness::NotConst);
for obligation in traits::elaborate_trait_ref(tcx, base_trait_ref) {
debug!(
"conv_object_ty_poly_trait_ref: observing object predicate `{:?}`",
obligation.predicate
);
let bound_predicate = obligation.predicate.bound_atom();
match bound_predicate.skip_binder() {
ty::PredicateAtom::Trait(pred, _) => {
let pred = bound_predicate.rebind(pred);
associated_types.entry(span).or_default().extend(
tcx.associated_items(pred.def_id())
.in_definition_order()
.filter(|item| item.kind == ty::AssocKind::Type)
.map(|item| item.def_id),
);
}
ty::PredicateAtom::Projection(pred) => {
let pred = bound_predicate.rebind(pred);
let references_self =
pred.skip_binder().ty.walk().any(|arg| arg == dummy_self.into());
if !references_self {
bounds.projection_bounds.push((pred, span));
}
}
_ => (),
}
}
}
for (projection_bound, _) in &bounds.projection_bounds {
for def_ids in associated_types.values_mut() {
def_ids.remove(&projection_bound.projection_def_id());
}
}
self.complain_about_missing_associated_types(
associated_types,
potential_assoc_types,
trait_bounds,
);
auto_traits.sort_by_key(|i| i.trait_ref().def_id());
auto_traits.dedup_by_key(|i| i.trait_ref().def_id());
debug!("regular_traits: {:?}", regular_traits);
debug!("auto_traits: {:?}", auto_traits);
let trait_ref_to_existential = |trait_ref: ty::TraitRef<'tcx>| {
if trait_ref.self_ty() != dummy_self {
tcx.sess.delay_span_bug(
DUMMY_SP,
&format!(
"trait_ref_to_existential called on {:?} with non-dummy Self",
trait_ref,
),
);
}
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
};
let existential_trait_refs =
regular_traits.iter().map(|i| i.trait_ref().map_bound(trait_ref_to_existential));
let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| {
bound.map_bound(|b| {
let trait_ref = trait_ref_to_existential(b.projection_ty.trait_ref(tcx));
ty::ExistentialProjection {
ty: b.ty,
item_def_id: b.projection_ty.item_def_id,
substs: trait_ref.substs,
}
})
});
let regular_trait_predicates = existential_trait_refs
.map(|trait_ref| ty::ExistentialPredicate::Trait(trait_ref.skip_binder()));
let auto_trait_predicates = auto_traits
.into_iter()
.map(|trait_ref| ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id()));
let mut v = regular_trait_predicates
.chain(auto_trait_predicates)
.chain(
existential_projections
.map(|x| ty::ExistentialPredicate::Projection(x.skip_binder())),
)
.collect::<SmallVec<[_; 8]>>();
v.sort_by(|a, b| a.stable_cmp(tcx, b));
v.dedup();
let existential_predicates = ty::Binder::bind(tcx.mk_existential_predicates(v.into_iter()));
let region_bound = if !lifetime.is_elided() {
self.ast_region_to_region(lifetime, None)
} else {
self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| {
if tcx.named_region(lifetime.hir_id).is_some() {
self.ast_region_to_region(lifetime, None)
} else {
self.re_infer(None, span).unwrap_or_else(|| {
let mut err = struct_span_err!(
tcx.sess,
span,
E0228,
"the lifetime bound for this object type cannot be deduced \
from context; please supply an explicit bound"
);
if borrowed {
err.delay_as_bug();
} else {
err.emit();
}
tcx.lifetimes.re_static
})
}
})
};
debug!("region_bound: {:?}", region_bound);
let ty = tcx.mk_dynamic(existential_predicates, region_bound);
debug!("trait_object_type: {:?}", ty);
ty
}
fn report_ambiguous_associated_type(
&self,
span: Span,
type_str: &str,
trait_str: &str,
name: Symbol,
) {
let mut err = struct_span_err!(self.tcx().sess, span, E0223, "ambiguous associated type");
if let (Some(_), Ok(snippet)) = (
self.tcx().sess.confused_type_with_std_module.borrow().get(&span),
self.tcx().sess.source_map().span_to_snippet(span),
) {
err.span_suggestion(
span,
"you are looking for the module in `std`, not the primitive type",
format!("std::{}", snippet),
Applicability::MachineApplicable,
);
} else {
err.span_suggestion(
span,
"use fully-qualified syntax",
format!("<{} as {}>::{}", type_str, trait_str, name),
Applicability::HasPlaceholders,
);
}
err.emit();
}
fn find_bound_for_assoc_item(
&self,
ty_param_def_id: LocalDefId,
assoc_name: Ident,
span: Span,
) -> Result<ty::PolyTraitRef<'tcx>, ErrorReported> {
let tcx = self.tcx();
debug!(
"find_bound_for_assoc_item(ty_param_def_id={:?}, assoc_name={:?}, span={:?})",
ty_param_def_id, assoc_name, span,
);
let predicates =
&self.get_type_parameter_bounds(span, ty_param_def_id.to_def_id()).predicates;
debug!("find_bound_for_assoc_item: predicates={:#?}", predicates);
let param_hir_id = tcx.hir().local_def_id_to_hir_id(ty_param_def_id);
let param_name = tcx.hir().ty_param_name(param_hir_id);
self.one_bound_for_assoc_type(
|| {
traits::transitive_bounds(
tcx,
predicates.iter().filter_map(|(p, _)| p.to_opt_poly_trait_ref()),
)
},
|| param_name.to_string(),
assoc_name,
span,
|| None,
)
}
fn one_bound_for_assoc_type<I>(
&self,
all_candidates: impl Fn() -> I,
ty_param_name: impl Fn() -> String,
assoc_name: Ident,
span: Span,
is_equality: impl Fn() -> Option<String>,
) -> Result<ty::PolyTraitRef<'tcx>, ErrorReported>
where
I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
{
let mut matching_candidates = all_candidates()
.filter(|r| self.trait_defines_associated_type_named(r.def_id(), assoc_name));
let bound = match matching_candidates.next() {
Some(bound) => bound,
None => {
self.complain_about_assoc_type_not_found(
all_candidates,
&ty_param_name(),
assoc_name,
span,
);
return Err(ErrorReported);
}
};
debug!("one_bound_for_assoc_type: bound = {:?}", bound);
if let Some(bound2) = matching_candidates.next() {
debug!("one_bound_for_assoc_type: bound2 = {:?}", bound2);
let is_equality = is_equality();
let bounds = array::IntoIter::new([bound, bound2]).chain(matching_candidates);
let mut err = if is_equality.is_some() {
struct_span_err!(
self.tcx().sess,
span,
E0222,
"ambiguous associated type `{}` in bounds of `{}`",
assoc_name,
ty_param_name()
)
} else {
struct_span_err!(
self.tcx().sess,
span,
E0221,
"ambiguous associated type `{}` in bounds of `{}`",
assoc_name,
ty_param_name()
)
};
err.span_label(span, format!("ambiguous associated type `{}`", assoc_name));
let mut where_bounds = vec![];
for bound in bounds {
let bound_id = bound.def_id();
let bound_span = self
.tcx()
.associated_items(bound_id)
.find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Type, bound_id)
.and_then(|item| self.tcx().hir().span_if_local(item.def_id));
if let Some(bound_span) = bound_span {
err.span_label(
bound_span,
format!(
"ambiguous `{}` from `{}`",
assoc_name,
bound.print_only_trait_path(),
),
);
if let Some(constraint) = &is_equality {
where_bounds.push(format!(
" T: {trait}::{assoc} = {constraint}",
trait=bound.print_only_trait_path(),
assoc=assoc_name,
constraint=constraint,
));
} else {
err.span_suggestion(
span,
"use fully qualified syntax to disambiguate",
format!(
"<{} as {}>::{}",
ty_param_name(),
bound.print_only_trait_path(),
assoc_name,
),
Applicability::MaybeIncorrect,
);
}
} else {
err.note(&format!(
"associated type `{}` could derive from `{}`",
ty_param_name(),
bound.print_only_trait_path(),
));
}
}
if !where_bounds.is_empty() {
err.help(&format!(
"consider introducing a new type parameter `T` and adding `where` constraints:\
\n where\n T: {},\n{}",
ty_param_name(),
where_bounds.join(",\n"),
));
}
err.emit();
if !where_bounds.is_empty() {
return Err(ErrorReported);
}
}
Ok(bound)
}
pub fn associated_path_to_ty(
&self,
hir_ref_id: hir::HirId,
span: Span,
qself_ty: Ty<'tcx>,
qself_res: Res,
assoc_segment: &hir::PathSegment<'_>,
permit_variants: bool,
) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorReported> {
let tcx = self.tcx();
let assoc_ident = assoc_segment.ident;
debug!("associated_path_to_ty: {:?}::{}", qself_ty, assoc_ident);
let mut variant_resolution = None;
if let ty::Adt(adt_def, _) = qself_ty.kind() {
if adt_def.is_enum() {
let variant_def = adt_def
.variants
.iter()
.find(|vd| tcx.hygienic_eq(assoc_ident, vd.ident, adt_def.did));
if let Some(variant_def) = variant_def {
if permit_variants {
tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span);
self.prohibit_generics(slice::from_ref(assoc_segment));
return Ok((qself_ty, DefKind::Variant, variant_def.def_id));
} else {
variant_resolution = Some(variant_def.def_id);
}
}
}
}
let bound = match (&qself_ty.kind(), qself_res) {
(_, Res::SelfTy(Some(_), Some((impl_def_id, _)))) => {
let trait_ref = match tcx.impl_trait_ref(impl_def_id) {
Some(trait_ref) => trait_ref,
None => {
return Err(ErrorReported);
}
};
self.one_bound_for_assoc_type(
|| traits::supertraits(tcx, ty::Binder::bind(trait_ref)),
|| "Self".to_string(),
assoc_ident,
span,
|| None,
)?
}
(
&ty::Param(_),
Res::SelfTy(Some(param_did), None) | Res::Def(DefKind::TyParam, param_did),
) => self.find_bound_for_assoc_item(param_did.expect_local(), assoc_ident, span)?,
_ => {
if variant_resolution.is_some() {
let msg = format!("expected type, found variant `{}`", assoc_ident);
tcx.sess.span_err(span, &msg);
} else if qself_ty.is_enum() {
let mut err = struct_span_err!(
tcx.sess,
assoc_ident.span,
E0599,
"no variant named `{}` found for enum `{}`",
assoc_ident,
qself_ty,
);
let adt_def = qself_ty.ty_adt_def().expect("enum is not an ADT");
if let Some(suggested_name) = find_best_match_for_name(
adt_def.variants.iter().map(|variant| &variant.ident.name),
assoc_ident.name,
None,
) {
err.span_suggestion(
assoc_ident.span,
"there is a variant with a similar name",
suggested_name.to_string(),
Applicability::MaybeIncorrect,
);
} else {
err.span_label(
assoc_ident.span,
format!("variant not found in `{}`", qself_ty),
);
}
if let Some(sp) = tcx.hir().span_if_local(adt_def.did) {
let sp = tcx.sess.source_map().guess_head_span(sp);
err.span_label(sp, format!("variant `{}` not found here", assoc_ident));
}
err.emit();
} else if !qself_ty.references_error() {
self.report_ambiguous_associated_type(
span,
&qself_ty.to_string(),
"Trait",
assoc_ident.name,
);
}
return Err(ErrorReported);
}
};
let trait_did = bound.def_id();
let (assoc_ident, def_scope) =
tcx.adjust_ident_and_get_scope(assoc_ident, trait_did, hir_ref_id);
let item = tcx
.associated_items(trait_did)
.in_definition_order()
.find(|i| {
i.kind.namespace() == Namespace::TypeNS
&& i.ident.normalize_to_macros_2_0() == assoc_ident
})
.expect("missing associated type");
let ty = self.projected_ty_from_poly_trait_ref(span, item.def_id, assoc_segment, bound);
let ty = self.normalize_ty(span, ty);
let kind = DefKind::AssocTy;
if !item.vis.is_accessible_from(def_scope, tcx) {
let kind = kind.descr(item.def_id);
let msg = format!("{} `{}` is private", kind, assoc_ident);
tcx.sess
.struct_span_err(span, &msg)
.span_label(span, &format!("private {}", kind))
.emit();
}
tcx.check_stability(item.def_id, Some(hir_ref_id), span);
if let Some(variant_def_id) = variant_resolution {
tcx.struct_span_lint_hir(AMBIGUOUS_ASSOCIATED_ITEMS, hir_ref_id, span, |lint| {
let mut err = lint.build("ambiguous associated item");
let mut could_refer_to = |kind: DefKind, def_id, also| {
let note_msg = format!(
"`{}` could{} refer to the {} defined here",
assoc_ident,
also,
kind.descr(def_id)
);
err.span_note(tcx.def_span(def_id), ¬e_msg);
};
could_refer_to(DefKind::Variant, variant_def_id, "");
could_refer_to(kind, item.def_id, " also");
err.span_suggestion(
span,
"use fully-qualified syntax",
format!("<{} as {}>::{}", qself_ty, tcx.item_name(trait_did), assoc_ident),
Applicability::MachineApplicable,
);
err.emit();
});
}
Ok((ty, kind, item.def_id))
}
fn qpath_to_ty(
&self,
span: Span,
opt_self_ty: Option<Ty<'tcx>>,
item_def_id: DefId,
trait_segment: &hir::PathSegment<'_>,
item_segment: &hir::PathSegment<'_>,
) -> Ty<'tcx> {
let tcx = self.tcx();
let trait_def_id = tcx.parent(item_def_id).unwrap();
debug!("qpath_to_ty: trait_def_id={:?}", trait_def_id);
let self_ty = if let Some(ty) = opt_self_ty {
ty
} else {
let path_str = tcx.def_path_str(trait_def_id);
let def_id = self.item_def_id();
debug!("qpath_to_ty: self.item_def_id()={:?}", def_id);
let parent_def_id = def_id
.and_then(|def_id| {
def_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
})
.map(|hir_id| tcx.hir().get_parent_did(hir_id).to_def_id());
debug!("qpath_to_ty: parent_def_id={:?}", parent_def_id);
let is_part_of_self_trait_constraints = def_id == Some(trait_def_id);
let is_part_of_fn_in_self_trait = parent_def_id == Some(trait_def_id);
let type_name = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
"Self"
} else {
"Type"
};
self.report_ambiguous_associated_type(
span,
type_name,
&path_str,
item_segment.ident.name,
);
return tcx.ty_error();
};
debug!("qpath_to_ty: self_type={:?}", self_ty);
let trait_ref = self.ast_path_to_mono_trait_ref(span, trait_def_id, self_ty, trait_segment);
let item_substs = self.create_substs_for_associated_item(
tcx,
span,
item_def_id,
item_segment,
trait_ref.substs,
);
debug!("qpath_to_ty: trait_ref={:?}", trait_ref);
self.normalize_ty(span, tcx.mk_projection(item_def_id, item_substs))
}
pub fn prohibit_generics<'a, T: IntoIterator<Item = &'a hir::PathSegment<'a>>>(
&self,
segments: T,
) -> bool {
let mut has_err = false;
for segment in segments {
let (mut err_for_lt, mut err_for_ty, mut err_for_ct) = (false, false, false);
for arg in segment.generic_args().args {
let (span, kind) = match arg {
hir::GenericArg::Lifetime(lt) => {
if err_for_lt {
continue;
}
err_for_lt = true;
has_err = true;
(lt.span, "lifetime")
}
hir::GenericArg::Type(ty) => {
if err_for_ty {
continue;
}
err_for_ty = true;
has_err = true;
(ty.span, "type")
}
hir::GenericArg::Const(ct) => {
if err_for_ct {
continue;
}
err_for_ct = true;
has_err = true;
(ct.span, "const")
}
};
let mut err = struct_span_err!(
self.tcx().sess,
span,
E0109,
"{} arguments are not allowed for this type",
kind,
);
err.span_label(span, format!("{} argument not allowed", kind));
err.emit();
if err_for_lt && err_for_ty && err_for_ct {
break;
}
}
if let [binding, ..] = segment.generic_args().bindings {
has_err = true;
Self::prohibit_assoc_ty_binding(self.tcx(), binding.span);
}
}
has_err
}
pub fn def_ids_for_value_path_segments(
&self,
segments: &[hir::PathSegment<'_>],
self_ty: Option<Ty<'tcx>>,
kind: DefKind,
def_id: DefId,
) -> Vec<PathSeg> {
let tcx = self.tcx();
assert!(!segments.is_empty());
let last = segments.len() - 1;
let mut path_segs = vec![];
match kind {
DefKind::Ctor(CtorOf::Struct, ..) => {
let generics = tcx.generics_of(def_id);
let generics_def_id = generics.parent.unwrap_or(def_id);
path_segs.push(PathSeg(generics_def_id, last));
}
DefKind::Ctor(CtorOf::Variant, ..) | DefKind::Variant => {
let adt_def = self_ty.map(|t| t.ty_adt_def().unwrap());
let (generics_def_id, index) = if let Some(adt_def) = adt_def {
debug_assert!(adt_def.is_enum());
(adt_def.did, last)
} else if last >= 1 && segments[last - 1].args.is_some() {
let mut def_id = def_id;
if let DefKind::Ctor(..) = kind {
def_id = tcx.parent(def_id).unwrap()
}
let enum_def_id = tcx.parent(def_id).unwrap();
(enum_def_id, last - 1)
} else {
let generics = tcx.generics_of(def_id);
(generics.parent.unwrap_or(def_id), last)
};
path_segs.push(PathSeg(generics_def_id, index));
}
DefKind::Fn | DefKind::Const | DefKind::ConstParam | DefKind::Static => {
path_segs.push(PathSeg(def_id, last));
}
DefKind::AssocFn | DefKind::AssocConst => {
if segments.len() >= 2 {
let generics = tcx.generics_of(def_id);
path_segs.push(PathSeg(generics.parent.unwrap(), last - 1));
}
path_segs.push(PathSeg(def_id, last));
}
kind => bug!("unexpected definition kind {:?} for {:?}", kind, def_id),
}
debug!("path_segs = {:?}", path_segs);
path_segs
}
pub fn res_to_ty(
&self,
opt_self_ty: Option<Ty<'tcx>>,
path: &hir::Path<'_>,
permit_variants: bool,
) -> Ty<'tcx> {
let tcx = self.tcx();
debug!(
"res_to_ty(res={:?}, opt_self_ty={:?}, path_segments={:?})",
path.res, opt_self_ty, path.segments
);
let span = path.span;
match path.res {
Res::Def(DefKind::OpaqueTy, did) => {
assert!(ty::is_impl_trait_defn(tcx, did).is_none());
let item_segment = path.segments.split_last().unwrap();
self.prohibit_generics(item_segment.1);
let substs = self.ast_path_substs_for_ty(span, did, item_segment.0);
self.normalize_ty(span, tcx.mk_opaque(did, substs))
}
Res::Def(
DefKind::Enum
| DefKind::TyAlias
| DefKind::Struct
| DefKind::Union
| DefKind::ForeignTy,
did,
) => {
assert_eq!(opt_self_ty, None);
self.prohibit_generics(path.segments.split_last().unwrap().1);
self.ast_path_to_ty(span, did, path.segments.last().unwrap())
}
Res::Def(kind @ DefKind::Variant, def_id) if permit_variants => {
assert_eq!(opt_self_ty, None);
let path_segs =
self.def_ids_for_value_path_segments(&path.segments, None, kind, def_id);
let generic_segs: FxHashSet<_> =
path_segs.iter().map(|PathSeg(_, index)| index).collect();
self.prohibit_generics(path.segments.iter().enumerate().filter_map(
|(index, seg)| {
if !generic_segs.contains(&index) { Some(seg) } else { None }
},
));
let PathSeg(def_id, index) = path_segs.last().unwrap();
self.ast_path_to_ty(span, *def_id, &path.segments[*index])
}
Res::Def(DefKind::TyParam, def_id) => {
assert_eq!(opt_self_ty, None);
self.prohibit_generics(path.segments);
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
let item_id = tcx.hir().get_parent_node(hir_id);
let item_def_id = tcx.hir().local_def_id(item_id);
let generics = tcx.generics_of(item_def_id);
let index = generics.param_def_id_to_index[&def_id];
tcx.mk_ty_param(index, tcx.hir().name(hir_id))
}
Res::SelfTy(Some(_), None) => {
assert_eq!(opt_self_ty, None);
self.prohibit_generics(path.segments);
tcx.types.self_param
}
Res::SelfTy(_, Some((def_id, forbid_generic))) => {
assert_eq!(opt_self_ty, None);
self.prohibit_generics(path.segments);
let normalized_ty = self.normalize_ty(span, tcx.at(span).type_of(def_id));
if forbid_generic && normalized_ty.needs_subst() {
let mut err = tcx.sess.struct_span_err(
path.span,
"generic `Self` types are currently not permitted in anonymous constants",
);
if let Some(hir::Node::Item(&hir::Item {
kind: hir::ItemKind::Impl { self_ty, .. },
..
})) = tcx.hir().get_if_local(def_id)
{
err.span_note(self_ty.span, "not a concrete type");
}
err.emit();
tcx.ty_error()
} else {
normalized_ty
}
}
Res::Def(DefKind::AssocTy, def_id) => {
debug_assert!(path.segments.len() >= 2);
self.prohibit_generics(&path.segments[..path.segments.len() - 2]);
self.qpath_to_ty(
span,
opt_self_ty,
def_id,
&path.segments[path.segments.len() - 2],
path.segments.last().unwrap(),
)
}
Res::PrimTy(prim_ty) => {
assert_eq!(opt_self_ty, None);
self.prohibit_generics(path.segments);
match prim_ty {
hir::PrimTy::Bool => tcx.types.bool,
hir::PrimTy::Char => tcx.types.char,
hir::PrimTy::Int(it) => tcx.mk_mach_int(it),
hir::PrimTy::Uint(uit) => tcx.mk_mach_uint(uit),
hir::PrimTy::Float(ft) => tcx.mk_mach_float(ft),
hir::PrimTy::Str => tcx.types.str_,
}
}
Res::Err => {
self.set_tainted_by_errors();
self.tcx().ty_error()
}
_ => span_bug!(span, "unexpected resolution: {:?}", path.res),
}
}
pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
self.ast_ty_to_ty_inner(ast_ty, false)
}
fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool) -> Ty<'tcx> {
debug!("ast_ty_to_ty(id={:?}, ast_ty={:?} ty_ty={:?})", ast_ty.hir_id, ast_ty, ast_ty.kind);
let tcx = self.tcx();
let result_ty = match ast_ty.kind {
hir::TyKind::Slice(ref ty) => tcx.mk_slice(self.ast_ty_to_ty(&ty)),
hir::TyKind::Ptr(ref mt) => {
tcx.mk_ptr(ty::TypeAndMut { ty: self.ast_ty_to_ty(&mt.ty), mutbl: mt.mutbl })
}
hir::TyKind::Rptr(ref region, ref mt) => {
let r = self.ast_region_to_region(region, None);
debug!("ast_ty_to_ty: r={:?}", r);
let t = self.ast_ty_to_ty_inner(&mt.ty, true);
tcx.mk_ref(r, ty::TypeAndMut { ty: t, mutbl: mt.mutbl })
}
hir::TyKind::Never => tcx.types.never,
hir::TyKind::Tup(ref fields) => {
tcx.mk_tup(fields.iter().map(|t| self.ast_ty_to_ty(&t)))
}
hir::TyKind::BareFn(ref bf) => {
require_c_abi_if_c_variadic(tcx, &bf.decl, bf.abi, ast_ty.span);
tcx.mk_fn_ptr(self.ty_of_fn(
bf.unsafety,
bf.abi,
&bf.decl,
&hir::Generics::empty(),
None,
))
}
hir::TyKind::TraitObject(ref bounds, ref lifetime) => {
self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed)
}
hir::TyKind::Path(hir::QPath::Resolved(ref maybe_qself, ref path)) => {
debug!("ast_ty_to_ty: maybe_qself={:?} path={:?}", maybe_qself, path);
let opt_self_ty = maybe_qself.as_ref().map(|qself| self.ast_ty_to_ty(qself));
self.res_to_ty(opt_self_ty, path, false)
}
hir::TyKind::OpaqueDef(item_id, ref lifetimes) => {
let opaque_ty = tcx.hir().expect_item(item_id.id);
let def_id = tcx.hir().local_def_id(item_id.id).to_def_id();
match opaque_ty.kind {
hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn, .. }) => {
self.impl_trait_ty_to_ty(def_id, lifetimes, impl_trait_fn.is_some())
}
ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
}
}
hir::TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => {
debug!("ast_ty_to_ty: qself={:?} segment={:?}", qself, segment);
let ty = self.ast_ty_to_ty(qself);
let res = if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = qself.kind {
path.res
} else {
Res::Err
};
self.associated_path_to_ty(ast_ty.hir_id, ast_ty.span, ty, res, segment, false)
.map(|(ty, _, _)| ty)
.unwrap_or_else(|_| tcx.ty_error())
}
hir::TyKind::Path(hir::QPath::LangItem(lang_item, span)) => {
let def_id = tcx.require_lang_item(lang_item, Some(span));
let (substs, _, _) = self.create_substs_for_ast_path(
span,
def_id,
&[],
&GenericArgs::none(),
true,
None,
);
self.normalize_ty(span, tcx.at(span).type_of(def_id).subst(tcx, substs))
}
hir::TyKind::Array(ref ty, ref length) => {
let length_def_id = tcx.hir().local_def_id(length.hir_id);
let length = ty::Const::from_anon_const(tcx, length_def_id);
let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(&ty), length));
self.normalize_ty(ast_ty.span, array_ty)
}
hir::TyKind::Typeof(ref _e) => {
tcx.sess.emit_err(TypeofReservedKeywordUsed { span: ast_ty.span });
tcx.ty_error()
}
hir::TyKind::Infer => {
self.ty_infer(None, ast_ty.span)
}
hir::TyKind::Err => tcx.ty_error(),
};
debug!("ast_ty_to_ty: result_ty={:?}", result_ty);
self.record_ty(ast_ty.hir_id, result_ty, ast_ty.span);
result_ty
}
pub fn impl_trait_ty_to_ty(
&self,
def_id: DefId,
lifetimes: &[hir::GenericArg<'_>],
replace_parent_lifetimes: bool,
) -> Ty<'tcx> {
debug!("impl_trait_ty_to_ty(def_id={:?}, lifetimes={:?})", def_id, lifetimes);
let tcx = self.tcx();
let generics = tcx.generics_of(def_id);
debug!("impl_trait_ty_to_ty: generics={:?}", generics);
let substs = InternalSubsts::for_item(tcx, def_id, |param, _| {
if let Some(i) = (param.index as usize).checked_sub(generics.parent_count) {
match param.kind {
GenericParamDefKind::Lifetime => {
if let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] {
self.ast_region_to_region(lifetime, None).into()
} else {
bug!()
}
}
_ => bug!(),
}
} else {
match param.kind {
GenericParamDefKind::Lifetime if replace_parent_lifetimes => {
tcx.lifetimes.re_static.into()
}
_ => tcx.mk_param_from_def(param),
}
}
});
debug!("impl_trait_ty_to_ty: substs={:?}", substs);
let ty = tcx.mk_opaque(def_id, substs);
debug!("impl_trait_ty_to_ty: {}", ty);
ty
}
pub fn ty_of_arg(&self, ty: &hir::Ty<'_>, expected_ty: Option<Ty<'tcx>>) -> Ty<'tcx> {
match ty.kind {
hir::TyKind::Infer if expected_ty.is_some() => {
self.record_ty(ty.hir_id, expected_ty.unwrap(), ty.span);
expected_ty.unwrap()
}
_ => self.ast_ty_to_ty(ty),
}
}
pub fn ty_of_fn(
&self,
unsafety: hir::Unsafety,
abi: abi::Abi,
decl: &hir::FnDecl<'_>,
generics: &hir::Generics<'_>,
ident_span: Option<Span>,
) -> ty::PolyFnSig<'tcx> {
debug!("ty_of_fn");
let tcx = self.tcx();
let mut visitor = PlaceholderHirTyCollector::default();
for ty in decl.inputs {
visitor.visit_ty(ty);
}
walk_generics(&mut visitor, generics);
let input_tys = decl.inputs.iter().map(|a| self.ty_of_arg(a, None));
let output_ty = match decl.output {
hir::FnRetTy::Return(ref output) => {
visitor.visit_ty(output);
self.ast_ty_to_ty(output)
}
hir::FnRetTy::DefaultReturn(..) => tcx.mk_unit(),
};
debug!("ty_of_fn: output_ty={:?}", output_ty);
let bare_fn_ty =
ty::Binder::bind(tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, unsafety, abi));
if !self.allow_ty_infer() {
crate::collect::placeholder_type_error(
tcx,
ident_span.map(|sp| sp.shrink_to_hi()),
&generics.params[..],
visitor.0,
true,
);
}
let inputs = bare_fn_ty.inputs();
let late_bound_in_args =
tcx.collect_constrained_late_bound_regions(&inputs.map_bound(|i| i.to_owned()));
let output = bare_fn_ty.output();
let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(&output);
self.validate_late_bound_regions(late_bound_in_args, late_bound_in_ret, |br_name| {
struct_span_err!(
tcx.sess,
decl.output.span(),
E0581,
"return type references {}, which is not constrained by the fn input types",
br_name
)
});
bare_fn_ty
}
fn validate_late_bound_regions(
&self,
constrained_regions: FxHashSet<ty::BoundRegion>,
referenced_regions: FxHashSet<ty::BoundRegion>,
generate_err: impl Fn(&str) -> rustc_errors::DiagnosticBuilder<'tcx>,
) {
for br in referenced_regions.difference(&constrained_regions) {
let br_name = match *br {
ty::BrNamed(_, name) => format!("lifetime `{}`", name),
ty::BrAnon(_) | ty::BrEnv => "an anonymous lifetime".to_string(),
};
let mut err = generate_err(&br_name);
if let ty::BrAnon(_) = *br {
err.note(
"lifetimes appearing in an associated type are not considered constrained",
);
}
err.emit();
}
}
fn compute_object_lifetime_bound(
&self,
span: Span,
existential_predicates: ty::Binder<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>,
) -> Option<ty::Region<'tcx>>
{
let tcx = self.tcx();
debug!("compute_opt_region_bound(existential_predicates={:?})", existential_predicates);
let derived_region_bounds = object_region_bounds(tcx, existential_predicates);
if derived_region_bounds.is_empty() {
return None;
}
if derived_region_bounds.iter().any(|&r| ty::ReStatic == *r) {
return Some(tcx.lifetimes.re_static);
}
let r = derived_region_bounds[0];
if derived_region_bounds[1..].iter().any(|r1| r != *r1) {
tcx.sess.emit_err(AmbiguousLifetimeBound { span });
}
Some(r)
}
}