+// ignore-tidy-filelength FIXME(#67418) Split up this file.
//! Conversion from AST representation of types to the `ty.rs` representation.
//! The main routine here is `ast_ty_to_ty()`; each use is parameterized by an
//! instance of `AstConv`.
+// ignore-tidy-filelength
+
use crate::collect::PlaceholderHirTyCollector;
use crate::lint;
use crate::middle::lang_items::SizedTraitLangItem;
use rustc::traits::error_reporting::report_object_safety_error;
use rustc::traits::wf::object_region_bounds;
use rustc::ty::subst::{self, InternalSubsts, Subst, SubstsRef};
-use rustc::ty::{self, Const, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::{self, Const, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
use rustc::ty::{GenericParamDef, GenericParamDefKind};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId};
use rustc_span::{MultiSpan, Span, DUMMY_SP};
use rustc_target::spec::abi;
use smallvec::SmallVec;
-use syntax::ast;
+use syntax::ast::{self, Constness};
use syntax::util::lev_distance::find_best_match_for_name;
use std::collections::BTreeSet;
use std::iter;
use std::slice;
-use rustc_error_codes::*;
+use rustc::mir::interpret::LitToConstInput;
#[derive(Debug)]
pub struct PathSeg(pub DefId, pub usize);
fn item_def_id(&self) -> Option<DefId>;
+ fn default_constness_for_trait_bounds(&self) -> Constness;
+
/// Returns predicates in scope of the form `X: Foo`, where `X` is
/// a type parameter `X` with the given id `def_id`. This is a
/// subset of the full set of predicates.
&self,
trait_ref: &hir::TraitRef<'_>,
span: Span,
+ constness: Constness,
self_ty: Ty<'tcx>,
bounds: &mut Bounds<'tcx>,
speculative: bool,
);
let poly_trait_ref = ty::Binder::bind(ty::TraitRef::new(trait_def_id, substs));
- bounds.trait_bounds.push((poly_trait_ref, span));
+ bounds.trait_bounds.push((poly_trait_ref, span, constness));
let mut dup_bindings = FxHashMap::default();
for binding in &assoc_bindings {
pub fn instantiate_poly_trait_ref(
&self,
poly_trait_ref: &hir::PolyTraitRef<'_>,
+ constness: Constness,
self_ty: Ty<'tcx>,
bounds: &mut Bounds<'tcx>,
) -> Option<Vec<Span>> {
self.instantiate_poly_trait_ref_inner(
&poly_trait_ref.trait_ref,
poly_trait_ref.span,
+ constness,
self_ty,
bounds,
false,
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)
+ 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::Outlives(ref l) => region_bounds.push(l),
}
}
- for bound in trait_bounds {
- let _ = self.instantiate_poly_trait_ref(bound, param_ty, bounds);
+ for (bound, constness) in trait_bounds {
+ let _ = self.instantiate_poly_trait_ref(bound, constness, param_ty, bounds);
}
bounds.region_bounds.extend(
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.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 }
// those that do.
self.one_bound_for_assoc_type(
|| traits::supertraits(tcx, trait_ref),
- &trait_ref.print_only_trait_path().to_string(),
+ || trait_ref.print_only_trait_path().to_string(),
binding.item_name,
path_span,
- match binding.kind {
+ || match binding.kind {
ConvertedBindingKind::Equality(ty) => Some(ty.to_string()),
_ => None,
},
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() {
- let cur_potential_assoc_types =
- self.instantiate_poly_trait_ref(trait_bound, dummy_self, &mut bounds);
+ let 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().flatten());
}
// Expand trait aliases recursively and check that only one regular (non-auto) trait
// is used and no 'maybe' bounds are used.
- let expanded_traits =
- traits::expand_trait_aliases(tcx, bounds.trait_bounds.iter().cloned());
+ let expanded_traits = traits::expand_trait_aliases(
+ tcx,
+ bounds.trait_bounds.iter().map(|&(a, b, _)| (a.clone(), 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 regular_traits_refs_spans = bounds
.trait_bounds
.into_iter()
- .filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));
+ .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, ast::Constness::NotConst);
- for (base_trait_ref, span) in regular_traits_refs_spans {
for trait_ref in traits::elaborate_trait_ref(tcx, base_trait_ref) {
debug!(
"conv_object_ty_poly_trait_ref: observing object predicate `{:?}`",
trait_ref
);
match trait_ref {
- ty::Predicate::Trait(pred) => {
+ ty::Predicate::Trait(pred, _) => {
associated_types.entry(span).or_default().extend(
tcx.associated_items(pred.def_id())
.filter(|item| item.kind == ty::AssocKind::Type)
predicates.iter().filter_map(|(p, _)| p.to_opt_poly_trait_ref()),
)
},
- ¶m_name.as_str(),
+ || param_name.to_string(),
assoc_name,
span,
- None,
+ || None,
)
}
fn one_bound_for_assoc_type<I>(
&self,
all_candidates: impl Fn() -> I,
- ty_param_name: &str,
+ ty_param_name: impl Fn() -> String,
assoc_name: ast::Ident,
span: Span,
- is_equality: Option<String>,
+ is_equality: impl Fn() -> Option<String>,
) -> Result<ty::PolyTraitRef<'tcx>, ErrorReported>
where
I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
None => {
self.complain_about_assoc_type_not_found(
all_candidates,
- ty_param_name,
+ &ty_param_name(),
assoc_name,
span,
);
if let Some(bound2) = matching_candidates.next() {
debug!("one_bound_for_assoc_type: bound2 = {:?}", bound2);
+ let is_equality = is_equality();
let bounds = iter::once(bound).chain(iter::once(bound2)).chain(matching_candidates);
let mut err = if is_equality.is_some() {
// More specific Error Index entry.
E0222,
"ambiguous associated type `{}` in bounds of `{}`",
assoc_name,
- ty_param_name
+ ty_param_name()
)
} else {
struct_span_err!(
E0221,
"ambiguous associated type `{}` in bounds of `{}`",
assoc_name,
- ty_param_name
+ ty_param_name()
)
};
err.span_label(span, format!("ambiguous associated type `{}`", assoc_name));
"use fully qualified syntax to disambiguate",
format!(
"<{} as {}>::{}",
- ty_param_name,
+ ty_param_name(),
bound.print_only_trait_path(),
assoc_name,
),
} else {
err.note(&format!(
"associated type `{}` could derive from `{}`",
- ty_param_name,
+ ty_param_name(),
bound.print_only_trait_path(),
));
}
err.help(&format!(
"consider introducing a new type parameter `T` and adding `where` constraints:\
\n where\n T: {},\n{}",
- ty_param_name,
+ ty_param_name(),
where_bounds.join(",\n"),
));
}
self.one_bound_for_assoc_type(
|| traits::supertraits(tcx, ty::Binder::bind(trait_ref)),
- "Self",
+ || "Self".to_string(),
assoc_ident,
span,
- None,
+ || None,
)?
}
(&ty::Param(_), Res::SelfTy(Some(param_did), None))
let tcx = self.tcx();
let def_id = tcx.hir().local_def_id(ast_const.hir_id);
- let mut const_ = ty::Const {
- val: ty::ConstKind::Unevaluated(
- def_id,
- InternalSubsts::identity_for_item(tcx, def_id),
- None,
- ),
- ty,
+ let expr = &tcx.hir().body(ast_const.body).value;
+
+ let lit_input = match expr.kind {
+ hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
+ hir::ExprKind::Unary(hir::UnOp::UnNeg, ref expr) => match expr.kind {
+ hir::ExprKind::Lit(ref lit) => {
+ Some(LitToConstInput { lit: &lit.node, ty, neg: true })
+ }
+ _ => None,
+ },
+ _ => None,
};
- let expr = &tcx.hir().body(ast_const.body).value;
- if let Some(def_id) = self.const_param_def_id(expr) {
+ if let Some(lit_input) = lit_input {
+ // If an error occurred, ignore that it's a literal and leave reporting the error up to
+ // mir.
+ if let Ok(c) = tcx.at(expr.span).lit_to_const(lit_input) {
+ return c;
+ }
+ }
+
+ let kind = if let Some(def_id) = self.const_param_def_id(expr) {
// Find the name and index of the const parameter by indexing the generics of the
// parent item and construct a `ParamConst`.
let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
let generics = tcx.generics_of(item_def_id);
let index = generics.param_def_id_to_index[&tcx.hir().local_def_id(hir_id)];
let name = tcx.hir().name(hir_id);
- const_.val = ty::ConstKind::Param(ty::ParamConst::new(index, name));
- }
-
- tcx.mk_const(const_)
+ ty::ConstKind::Param(ty::ParamConst::new(index, name))
+ } else {
+ ty::ConstKind::Unevaluated(def_id, InternalSubsts::identity_for_item(tcx, def_id), None)
+ };
+ tcx.mk_const(ty::Const { val: kind, ty })
}
pub fn impl_trait_ty_to_ty(
/// A list of trait bounds. So if you had `T: Debug` this would be
/// `T: Debug`. Note that the self-type is explicit here.
- pub trait_bounds: Vec<(ty::PolyTraitRef<'tcx>, Span)>,
+ pub trait_bounds: Vec<(ty::PolyTraitRef<'tcx>, Span, Constness)>,
/// A list of projection equality bounds. So if you had `T:
/// Iterator<Item = u32>` this would include `<T as
def_id: sized,
substs: tcx.mk_substs_trait(param_ty, &[]),
});
- (trait_ref.to_predicate(), span)
+ (trait_ref.without_const().to_predicate(), span)
})
});
let outlives = ty::OutlivesPredicate(param_ty, region_bound);
(ty::Binder::bind(outlives).to_predicate(), span)
})
- .chain(
- self.trait_bounds
- .iter()
- .map(|&(bound_trait_ref, span)| (bound_trait_ref.to_predicate(), span)),
- )
+ .chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| {
+ let predicate = bound_trait_ref.with_constness(constness).to_predicate();
+ (predicate, span)
+ }))
.chain(
self.projection_bounds
.iter()