Auto merge of #33137 - nikomatsakis:issue-32330-lbr-in-return-type-warning-2, r=aturon
Warnings for issue #32330 This is an extension of the previous PR that issues warnings in more situations than before. It does not handle *all* cases of #32330 but I believe it issues warnings for all cases I've seen in practice. Before merging I'd like to address: - open a good issue explaining the problem and how to fix it (I have a [draft writeup][]) - work on the error message, which I think is not as clear as it could/should be (suggestions welcome) r? @aturon [draft writeup]: https://gist.github.com/nikomatsakis/631ec8b4af9a18b5d062d9d9b7d3d967
This commit is contained in:
commit
75e23e1b03
@ -167,6 +167,13 @@ declare_lint! {
|
||||
"transmute from function item type to pointer-sized type erroneously allowed"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
pub HR_LIFETIME_IN_ASSOC_TYPE,
|
||||
Warn,
|
||||
"binding for associated type references higher-ranked lifetime \
|
||||
that does not appear in the trait input types"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
pub OVERLAPPING_INHERENT_IMPLS,
|
||||
Warn,
|
||||
@ -234,7 +241,8 @@ impl LintPass for HardwiredLints {
|
||||
RENAMED_AND_REMOVED_LINTS,
|
||||
SUPER_OR_SELF_IN_GLOBAL_PATH,
|
||||
UNSIZED_IN_TUPLE,
|
||||
OBJECT_UNSAFE_FRAGMENT
|
||||
OBJECT_UNSAFE_FRAGMENT,
|
||||
HR_LIFETIME_IN_ASSOC_TYPE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -152,14 +152,8 @@ enum ProjectionTyCandidate<'tcx> {
|
||||
// from the definition of `Trait` when you have something like <<A as Trait>::B as Trait2>::C
|
||||
TraitDef(ty::PolyProjectionPredicate<'tcx>),
|
||||
|
||||
// defined in an impl
|
||||
Impl(VtableImplData<'tcx, PredicateObligation<'tcx>>),
|
||||
|
||||
// closure return type
|
||||
Closure(VtableClosureData<'tcx, PredicateObligation<'tcx>>),
|
||||
|
||||
// fn pointer return type
|
||||
FnPointer(VtableFnPointerData<'tcx, PredicateObligation<'tcx>>),
|
||||
// from a "impl" (or a "pseudo-impl" returned by select)
|
||||
Select,
|
||||
}
|
||||
|
||||
struct ProjectionTyCandidateSet<'tcx> {
|
||||
@ -599,10 +593,8 @@ fn project_type<'cx, 'gcx, 'tcx>(
|
||||
debug!("retaining param-env candidates only from {:?}", candidates.vec);
|
||||
candidates.vec.retain(|c| match *c {
|
||||
ProjectionTyCandidate::ParamEnv(..) => true,
|
||||
ProjectionTyCandidate::Impl(..) |
|
||||
ProjectionTyCandidate::Closure(..) |
|
||||
ProjectionTyCandidate::TraitDef(..) |
|
||||
ProjectionTyCandidate::FnPointer(..) => false,
|
||||
ProjectionTyCandidate::Select => false,
|
||||
});
|
||||
debug!("resulting candidate set: {:?}", candidates.vec);
|
||||
if candidates.vec.len() != 1 {
|
||||
@ -612,78 +604,12 @@ fn project_type<'cx, 'gcx, 'tcx>(
|
||||
|
||||
assert!(candidates.vec.len() <= 1);
|
||||
|
||||
let possible_candidate = candidates.vec.pop().and_then(|candidate| {
|
||||
// In Any (i.e. trans) mode, all projections succeed;
|
||||
// otherwise, we need to be sensitive to `default` and
|
||||
// specialization.
|
||||
if !selcx.projection_mode().is_any() {
|
||||
if let ProjectionTyCandidate::Impl(ref impl_data) = candidate {
|
||||
if let Some(node_item) = assoc_ty_def(selcx,
|
||||
impl_data.impl_def_id,
|
||||
obligation.predicate.item_name) {
|
||||
if node_item.node.is_from_trait() {
|
||||
if node_item.item.ty.is_some() {
|
||||
// If the associated type has a default from the
|
||||
// trait, that should be considered `default` and
|
||||
// hence not projected.
|
||||
//
|
||||
// Note, however, that we allow a projection from
|
||||
// the trait specifically in the case that the trait
|
||||
// does *not* give a default. This is purely to
|
||||
// avoid spurious errors: the situation can only
|
||||
// arise when *no* impl in the specialization chain
|
||||
// has provided a definition for the type. When we
|
||||
// confirm the candidate, we'll turn the projection
|
||||
// into a TyError, since the actual error will be
|
||||
// reported in `check_impl_items_against_trait`.
|
||||
return None;
|
||||
}
|
||||
} else if node_item.item.defaultness.is_default() {
|
||||
return None;
|
||||
}
|
||||
} else {
|
||||
// Normally this situation could only arise througha
|
||||
// compiler bug, but at coherence-checking time we only look
|
||||
// at the topmost impl (we don't even consider the trait
|
||||
// itself) for the definition -- so we can fail to find a
|
||||
// definition of the type even if it exists.
|
||||
|
||||
// For now, we just unconditionally ICE, because otherwise,
|
||||
// examples like the following will succeed:
|
||||
//
|
||||
// ```
|
||||
// trait Assoc {
|
||||
// type Output;
|
||||
// }
|
||||
//
|
||||
// impl<T> Assoc for T {
|
||||
// default type Output = bool;
|
||||
// }
|
||||
//
|
||||
// impl Assoc for u8 {}
|
||||
// impl Assoc for u16 {}
|
||||
//
|
||||
// trait Foo {}
|
||||
// impl Foo for <u8 as Assoc>::Output {}
|
||||
// impl Foo for <u16 as Assoc>::Output {}
|
||||
// return None;
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// The essential problem here is that the projection fails,
|
||||
// leaving two unnormalized types, which appear not to unify
|
||||
// -- so the overlap check succeeds, when it should fail.
|
||||
bug!("Tried to project an inherited associated type during \
|
||||
coherence checking, which is currently not supported.");
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(candidate)
|
||||
});
|
||||
|
||||
match possible_candidate {
|
||||
match candidates.vec.pop() {
|
||||
Some(candidate) => {
|
||||
let (ty, obligations) = confirm_candidate(selcx, obligation, candidate);
|
||||
let (ty, obligations) = confirm_candidate(selcx,
|
||||
obligation,
|
||||
&obligation_trait_ref,
|
||||
candidate);
|
||||
Ok(ProjectedTy::Progress(ty, obligations))
|
||||
}
|
||||
None => {
|
||||
@ -802,38 +728,6 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>(
|
||||
}
|
||||
}
|
||||
|
||||
fn assemble_candidates_from_object_type<'cx, 'gcx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
obligation_trait_ref: &ty::TraitRef<'tcx>,
|
||||
candidate_set: &mut ProjectionTyCandidateSet<'tcx>)
|
||||
{
|
||||
let self_ty = obligation_trait_ref.self_ty();
|
||||
let object_ty = selcx.infcx().shallow_resolve(self_ty);
|
||||
debug!("assemble_candidates_from_object_type(object_ty={:?})",
|
||||
object_ty);
|
||||
let data = match object_ty.sty {
|
||||
ty::TyTrait(ref data) => data,
|
||||
_ => {
|
||||
span_bug!(
|
||||
obligation.cause.span,
|
||||
"assemble_candidates_from_object_type called with non-object: {:?}",
|
||||
object_ty);
|
||||
}
|
||||
};
|
||||
let projection_bounds = data.projection_bounds_with_self_ty(selcx.tcx(), object_ty);
|
||||
let env_predicates = projection_bounds.iter()
|
||||
.map(|p| p.to_predicate())
|
||||
.collect();
|
||||
let env_predicates = elaborate_predicates(selcx.tcx(), env_predicates);
|
||||
assemble_candidates_from_predicates(selcx,
|
||||
obligation,
|
||||
obligation_trait_ref,
|
||||
candidate_set,
|
||||
ProjectionTyCandidate::ParamEnv,
|
||||
env_predicates)
|
||||
}
|
||||
|
||||
fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
@ -845,82 +739,183 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
|
||||
// start out by selecting the predicate `T as TraitRef<...>`:
|
||||
let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
|
||||
let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate());
|
||||
let vtable = match selcx.select(&trait_obligation) {
|
||||
Ok(Some(vtable)) => vtable,
|
||||
Ok(None) => {
|
||||
candidate_set.ambiguous = true;
|
||||
return Ok(());
|
||||
}
|
||||
Err(e) => {
|
||||
debug!("assemble_candidates_from_impls: selection error {:?}",
|
||||
e);
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
selcx.infcx().probe(|_| {
|
||||
let vtable = match selcx.select(&trait_obligation) {
|
||||
Ok(Some(vtable)) => vtable,
|
||||
Ok(None) => {
|
||||
candidate_set.ambiguous = true;
|
||||
return Ok(());
|
||||
}
|
||||
Err(e) => {
|
||||
debug!("assemble_candidates_from_impls: selection error {:?}",
|
||||
e);
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
|
||||
match vtable {
|
||||
super::VtableImpl(data) => {
|
||||
debug!("assemble_candidates_from_impls: impl candidate {:?}",
|
||||
data);
|
||||
match vtable {
|
||||
super::VtableClosure(_) |
|
||||
super::VtableFnPointer(_) |
|
||||
super::VtableObject(_) => {
|
||||
debug!("assemble_candidates_from_impls: vtable={:?}",
|
||||
vtable);
|
||||
|
||||
candidate_set.vec.push(
|
||||
ProjectionTyCandidate::Impl(data));
|
||||
candidate_set.vec.push(ProjectionTyCandidate::Select);
|
||||
}
|
||||
super::VtableImpl(ref impl_data) if !selcx.projection_mode().is_any() => {
|
||||
// We have to be careful when projecting out of an
|
||||
// impl because of specialization. If we are not in
|
||||
// trans (i.e., projection mode is not "any"), and the
|
||||
// impl's type is declared as default, then we disable
|
||||
// projection (even if the trait ref is fully
|
||||
// monomorphic). In the case where trait ref is not
|
||||
// fully monomorphic (i.e., includes type parameters),
|
||||
// this is because those type parameters may
|
||||
// ultimately be bound to types from other crates that
|
||||
// may have specialized impls we can't see. In the
|
||||
// case where the trait ref IS fully monomorphic, this
|
||||
// is a policy decision that we made in the RFC in
|
||||
// order to preserve flexibility for the crate that
|
||||
// defined the specializable impl to specialize later
|
||||
// for existing types.
|
||||
//
|
||||
// In either case, we handle this by not adding a
|
||||
// candidate for an impl if it contains a `default`
|
||||
// type.
|
||||
let opt_node_item = assoc_ty_def(selcx,
|
||||
impl_data.impl_def_id,
|
||||
obligation.predicate.item_name);
|
||||
let new_candidate = if let Some(node_item) = opt_node_item {
|
||||
if node_item.node.is_from_trait() {
|
||||
if node_item.item.ty.is_some() {
|
||||
// The impl inherited a `type Foo =
|
||||
// Bar` given in the trait, which is
|
||||
// implicitly default. No candidate.
|
||||
None
|
||||
} else {
|
||||
// The impl did not specify `type` and neither
|
||||
// did the trait:
|
||||
//
|
||||
// ```rust
|
||||
// trait Foo { type T; }
|
||||
// impl Foo for Bar { }
|
||||
// ```
|
||||
//
|
||||
// This is an error, but it will be
|
||||
// reported in `check_impl_items_against_trait`.
|
||||
// We accept it here but will flag it as
|
||||
// an error when we confirm the candidate
|
||||
// (which will ultimately lead to `normalize_to_error`
|
||||
// being invoked).
|
||||
Some(ProjectionTyCandidate::Select)
|
||||
}
|
||||
} else if node_item.item.defaultness.is_default() {
|
||||
// The impl specified `default type Foo =
|
||||
// Bar`. No candidate.
|
||||
None
|
||||
} else {
|
||||
// The impl specified `type Foo = Bar`
|
||||
// with no default. Add a candidate.
|
||||
Some(ProjectionTyCandidate::Select)
|
||||
}
|
||||
} else {
|
||||
// This is saying that neither the trait nor
|
||||
// the impl contain a definition for this
|
||||
// associated type. Normally this situation
|
||||
// could only arise through a compiler bug --
|
||||
// if the user wrote a bad item name, it
|
||||
// should have failed in astconv. **However**,
|
||||
// at coherence-checking time, we only look at
|
||||
// the topmost impl (we don't even consider
|
||||
// the trait itself) for the definition -- and
|
||||
// so in that case it may be that the trait
|
||||
// *DOES* have a declaration, but we don't see
|
||||
// it, and we end up in this branch.
|
||||
//
|
||||
// This is kind of tricky to handle actually.
|
||||
// For now, we just unconditionally ICE,
|
||||
// because otherwise, examples like the
|
||||
// following will succeed:
|
||||
//
|
||||
// ```
|
||||
// trait Assoc {
|
||||
// type Output;
|
||||
// }
|
||||
//
|
||||
// impl<T> Assoc for T {
|
||||
// default type Output = bool;
|
||||
// }
|
||||
//
|
||||
// impl Assoc for u8 {}
|
||||
// impl Assoc for u16 {}
|
||||
//
|
||||
// trait Foo {}
|
||||
// impl Foo for <u8 as Assoc>::Output {}
|
||||
// impl Foo for <u16 as Assoc>::Output {}
|
||||
// return None;
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// The essential problem here is that the
|
||||
// projection fails, leaving two unnormalized
|
||||
// types, which appear not to unify -- so the
|
||||
// overlap check succeeds, when it should
|
||||
// fail.
|
||||
bug!("Tried to project an inherited associated type during \
|
||||
coherence checking, which is currently not supported.");
|
||||
};
|
||||
candidate_set.vec.extend(new_candidate);
|
||||
}
|
||||
super::VtableImpl(_) => {
|
||||
// In trans mode, we can just project out of impls, no prob.
|
||||
assert!(selcx.projection_mode().is_any());
|
||||
candidate_set.vec.push(ProjectionTyCandidate::Select);
|
||||
}
|
||||
super::VtableParam(..) => {
|
||||
// This case tell us nothing about the value of an
|
||||
// associated type. Consider:
|
||||
//
|
||||
// ```
|
||||
// trait SomeTrait { type Foo; }
|
||||
// fn foo<T:SomeTrait>(...) { }
|
||||
// ```
|
||||
//
|
||||
// If the user writes `<T as SomeTrait>::Foo`, then the `T
|
||||
// : SomeTrait` binding does not help us decide what the
|
||||
// type `Foo` is (at least, not more specifically than
|
||||
// what we already knew).
|
||||
//
|
||||
// But wait, you say! What about an example like this:
|
||||
//
|
||||
// ```
|
||||
// fn bar<T:SomeTrait<Foo=usize>>(...) { ... }
|
||||
// ```
|
||||
//
|
||||
// Doesn't the `T : Sometrait<Foo=usize>` predicate help
|
||||
// resolve `T::Foo`? And of course it does, but in fact
|
||||
// that single predicate is desugared into two predicates
|
||||
// in the compiler: a trait predicate (`T : SomeTrait`) and a
|
||||
// projection. And the projection where clause is handled
|
||||
// in `assemble_candidates_from_param_env`.
|
||||
}
|
||||
super::VtableDefaultImpl(..) |
|
||||
super::VtableBuiltin(..) => {
|
||||
// These traits have no associated types.
|
||||
span_bug!(
|
||||
obligation.cause.span,
|
||||
"Cannot project an associated type from `{:?}`",
|
||||
vtable);
|
||||
}
|
||||
}
|
||||
super::VtableObject(_) => {
|
||||
assemble_candidates_from_object_type(
|
||||
selcx, obligation, obligation_trait_ref, candidate_set);
|
||||
}
|
||||
super::VtableClosure(data) => {
|
||||
candidate_set.vec.push(
|
||||
ProjectionTyCandidate::Closure(data));
|
||||
}
|
||||
super::VtableFnPointer(data) => {
|
||||
candidate_set.vec.push(
|
||||
ProjectionTyCandidate::FnPointer(data));
|
||||
}
|
||||
super::VtableParam(..) => {
|
||||
// This case tell us nothing about the value of an
|
||||
// associated type. Consider:
|
||||
//
|
||||
// ```
|
||||
// trait SomeTrait { type Foo; }
|
||||
// fn foo<T:SomeTrait>(...) { }
|
||||
// ```
|
||||
//
|
||||
// If the user writes `<T as SomeTrait>::Foo`, then the `T
|
||||
// : SomeTrait` binding does not help us decide what the
|
||||
// type `Foo` is (at least, not more specifically than
|
||||
// what we already knew).
|
||||
//
|
||||
// But wait, you say! What about an example like this:
|
||||
//
|
||||
// ```
|
||||
// fn bar<T:SomeTrait<Foo=usize>>(...) { ... }
|
||||
// ```
|
||||
//
|
||||
// Doesn't the `T : Sometrait<Foo=usize>` predicate help
|
||||
// resolve `T::Foo`? And of course it does, but in fact
|
||||
// that single predicate is desugared into two predicates
|
||||
// in the compiler: a trait predicate (`T : SomeTrait`) and a
|
||||
// projection. And the projection where clause is handled
|
||||
// in `assemble_candidates_from_param_env`.
|
||||
}
|
||||
super::VtableDefaultImpl(..) |
|
||||
super::VtableBuiltin(..) => {
|
||||
// These traits have no associated types.
|
||||
span_bug!(
|
||||
obligation.cause.span,
|
||||
"Cannot project an associated type from `{:?}`",
|
||||
vtable);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn confirm_candidate<'cx, 'gcx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
obligation_trait_ref: &ty::TraitRef<'tcx>,
|
||||
candidate: ProjectionTyCandidate<'tcx>)
|
||||
-> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
|
||||
{
|
||||
@ -934,20 +929,118 @@ fn confirm_candidate<'cx, 'gcx, 'tcx>(
|
||||
confirm_param_env_candidate(selcx, obligation, poly_projection)
|
||||
}
|
||||
|
||||
ProjectionTyCandidate::Impl(impl_vtable) => {
|
||||
confirm_impl_candidate(selcx, obligation, impl_vtable)
|
||||
}
|
||||
|
||||
ProjectionTyCandidate::Closure(closure_vtable) => {
|
||||
confirm_closure_candidate(selcx, obligation, closure_vtable)
|
||||
}
|
||||
|
||||
ProjectionTyCandidate::FnPointer(fn_pointer_vtable) => {
|
||||
confirm_fn_pointer_candidate(selcx, obligation, fn_pointer_vtable)
|
||||
ProjectionTyCandidate::Select => {
|
||||
confirm_select_candidate(selcx, obligation, obligation_trait_ref)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn confirm_select_candidate<'cx, 'gcx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
obligation_trait_ref: &ty::TraitRef<'tcx>)
|
||||
-> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
|
||||
{
|
||||
let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
|
||||
let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate());
|
||||
let vtable = match selcx.select(&trait_obligation) {
|
||||
Ok(Some(vtable)) => vtable,
|
||||
_ => {
|
||||
span_bug!(
|
||||
obligation.cause.span,
|
||||
"Failed to select `{:?}`",
|
||||
trait_obligation);
|
||||
}
|
||||
};
|
||||
|
||||
match vtable {
|
||||
super::VtableImpl(data) =>
|
||||
confirm_impl_candidate(selcx, obligation, data),
|
||||
super::VtableClosure(data) =>
|
||||
confirm_closure_candidate(selcx, obligation, data),
|
||||
super::VtableFnPointer(data) =>
|
||||
confirm_fn_pointer_candidate(selcx, obligation, data),
|
||||
super::VtableObject(_) =>
|
||||
confirm_object_candidate(selcx, obligation, obligation_trait_ref),
|
||||
super::VtableDefaultImpl(..) |
|
||||
super::VtableParam(..) |
|
||||
super::VtableBuiltin(..) =>
|
||||
// we don't create Select candidates with this kind of resolution
|
||||
span_bug!(
|
||||
obligation.cause.span,
|
||||
"Cannot project an associated type from `{:?}`",
|
||||
vtable),
|
||||
}
|
||||
}
|
||||
|
||||
fn confirm_object_candidate<'cx, 'gcx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
obligation_trait_ref: &ty::TraitRef<'tcx>)
|
||||
-> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
|
||||
{
|
||||
let self_ty = obligation_trait_ref.self_ty();
|
||||
let object_ty = selcx.infcx().shallow_resolve(self_ty);
|
||||
debug!("confirm_object_candidate(object_ty={:?})",
|
||||
object_ty);
|
||||
let data = match object_ty.sty {
|
||||
ty::TyTrait(ref data) => data,
|
||||
_ => {
|
||||
span_bug!(
|
||||
obligation.cause.span,
|
||||
"confirm_object_candidate called with non-object: {:?}",
|
||||
object_ty);
|
||||
}
|
||||
};
|
||||
let projection_bounds = data.projection_bounds_with_self_ty(selcx.tcx(), object_ty);
|
||||
let env_predicates = projection_bounds.iter()
|
||||
.map(|p| p.to_predicate())
|
||||
.collect();
|
||||
let env_predicate = {
|
||||
let env_predicates = elaborate_predicates(selcx.tcx(), env_predicates);
|
||||
|
||||
// select only those projections that are actually projecting an
|
||||
// item with the correct name
|
||||
let env_predicates = env_predicates.filter_map(|p| match p {
|
||||
ty::Predicate::Projection(data) =>
|
||||
if data.item_name() == obligation.predicate.item_name {
|
||||
Some(data)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
_ => None
|
||||
});
|
||||
|
||||
// select those with a relevant trait-ref
|
||||
let mut env_predicates = env_predicates.filter(|data| {
|
||||
let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span);
|
||||
let data_poly_trait_ref = data.to_poly_trait_ref();
|
||||
let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
|
||||
selcx.infcx().probe(|_| {
|
||||
selcx.infcx().sub_poly_trait_refs(false,
|
||||
origin,
|
||||
data_poly_trait_ref,
|
||||
obligation_poly_trait_ref).is_ok()
|
||||
})
|
||||
});
|
||||
|
||||
// select the first matching one; there really ought to be one or
|
||||
// else the object type is not WF, since an object type should
|
||||
// include all of its projections explicitly
|
||||
match env_predicates.next() {
|
||||
Some(env_predicate) => env_predicate,
|
||||
None => {
|
||||
debug!("confirm_object_candidate: no env-predicate \
|
||||
found in object type `{:?}`; ill-formed",
|
||||
object_ty);
|
||||
return (selcx.tcx().types.err, vec!());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
confirm_param_env_candidate(selcx, obligation, env_predicate)
|
||||
}
|
||||
|
||||
fn confirm_fn_pointer_candidate<'cx, 'gcx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
|
@ -382,6 +382,35 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a set of all late-bound regions that are constrained
|
||||
/// by `value`, meaning that if we instantiate those LBR with
|
||||
/// variables and equate `value` with something else, those
|
||||
/// variables will also be equated.
|
||||
pub fn collect_constrained_late_bound_regions<T>(&self, value: &Binder<T>)
|
||||
-> FnvHashSet<ty::BoundRegion>
|
||||
where T : TypeFoldable<'tcx>
|
||||
{
|
||||
self.collect_late_bound_regions(value, true)
|
||||
}
|
||||
|
||||
/// Returns a set of all late-bound regions that appear in `value` anywhere.
|
||||
pub fn collect_referenced_late_bound_regions<T>(&self, value: &Binder<T>)
|
||||
-> FnvHashSet<ty::BoundRegion>
|
||||
where T : TypeFoldable<'tcx>
|
||||
{
|
||||
self.collect_late_bound_regions(value, false)
|
||||
}
|
||||
|
||||
fn collect_late_bound_regions<T>(&self, value: &Binder<T>, just_constraint: bool)
|
||||
-> FnvHashSet<ty::BoundRegion>
|
||||
where T : TypeFoldable<'tcx>
|
||||
{
|
||||
let mut collector = LateBoundRegionsCollector::new(just_constraint);
|
||||
let result = value.skip_binder().visit_with(&mut collector);
|
||||
assert!(!result); // should never have stopped early
|
||||
collector.regions
|
||||
}
|
||||
|
||||
/// Replace any late-bound regions bound in `value` with `'static`. Useful in trans but also
|
||||
/// method lookup and a few other places where precise region relationships are not required.
|
||||
pub fn erase_late_bound_regions<T>(self, value: &Binder<T>) -> T
|
||||
@ -625,3 +654,54 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Collects all the late-bound regions it finds into a hash set.
|
||||
struct LateBoundRegionsCollector {
|
||||
current_depth: u32,
|
||||
regions: FnvHashSet<ty::BoundRegion>,
|
||||
just_constrained: bool,
|
||||
}
|
||||
|
||||
impl LateBoundRegionsCollector {
|
||||
fn new(just_constrained: bool) -> Self {
|
||||
LateBoundRegionsCollector {
|
||||
current_depth: 1,
|
||||
regions: FnvHashSet(),
|
||||
just_constrained: just_constrained,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector {
|
||||
fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> bool {
|
||||
self.current_depth += 1;
|
||||
let result = t.super_visit_with(self);
|
||||
self.current_depth -= 1;
|
||||
result
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
|
||||
// if we are only looking for "constrained" region, we have to
|
||||
// ignore the inputs to a projection, as they may not appear
|
||||
// in the normalized form
|
||||
if self.just_constrained {
|
||||
match t.sty {
|
||||
ty::TyProjection(..) => { return false; }
|
||||
_ => { }
|
||||
}
|
||||
}
|
||||
|
||||
t.super_visit_with(self)
|
||||
}
|
||||
|
||||
fn visit_region(&mut self, r: ty::Region) -> bool {
|
||||
match r {
|
||||
ty::ReLateBound(debruijn, br) if debruijn.depth == self.current_depth => {
|
||||
self.regions.insert(br);
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -197,7 +197,11 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
|
||||
FutureIncompatibleInfo {
|
||||
id: LintId::of(OBJECT_UNSAFE_FRAGMENT),
|
||||
reference: "issue #33243 <https://github.com/rust-lang/rust/issues/33243>",
|
||||
}
|
||||
},
|
||||
FutureIncompatibleInfo {
|
||||
id: LintId::of(HR_LIFETIME_IN_ASSOC_TYPE),
|
||||
reference: "issue #33685 <https://github.com/rust-lang/rust/issues/33685>",
|
||||
},
|
||||
]);
|
||||
|
||||
// We have one lint pass defined specially
|
||||
|
@ -52,13 +52,17 @@ use middle::const_val::ConstVal;
|
||||
use rustc_const_eval::{eval_const_expr_partial, ConstEvalErr};
|
||||
use rustc_const_eval::EvalHint::UncheckedExprHint;
|
||||
use rustc_const_eval::ErrKind::ErroneousReferencedConstant;
|
||||
use hir::{self, SelfKind};
|
||||
use hir::def::{self, Def};
|
||||
use hir::def_id::DefId;
|
||||
use hir::print as pprust;
|
||||
use middle::resolve_lifetime as rl;
|
||||
use rustc::lint;
|
||||
use rustc::ty::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs, ParamSpace};
|
||||
use rustc::traits;
|
||||
use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable};
|
||||
use rustc::ty::wf::object_region_bounds;
|
||||
use rustc_back::slice;
|
||||
use require_c_abi_if_variadic;
|
||||
use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope,
|
||||
ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope,
|
||||
@ -74,10 +78,6 @@ use syntax::errors::DiagnosticBuilder;
|
||||
use syntax::feature_gate::{GateIssue, emit_feature_err};
|
||||
use syntax::parse::token::{self, keywords};
|
||||
|
||||
use rustc::hir::print as pprust;
|
||||
use rustc::hir::{self, SelfKind};
|
||||
use rustc_back::slice;
|
||||
|
||||
pub trait AstConv<'gcx, 'tcx> {
|
||||
fn tcx<'a>(&'a self) -> TyCtxt<'a, 'gcx, 'tcx>;
|
||||
|
||||
@ -679,6 +679,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||
PathParamMode::Explicit,
|
||||
trait_def_id,
|
||||
self_ty,
|
||||
trait_ref.ref_id,
|
||||
trait_ref.path.segments.last().unwrap(),
|
||||
poly_projections)
|
||||
}
|
||||
@ -723,6 +724,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||
span: Span,
|
||||
param_mode: PathParamMode,
|
||||
trait_def_id: DefId,
|
||||
trait_path_ref_id: ast::NodeId,
|
||||
trait_segment: &hir::PathSegment,
|
||||
mut projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
|
||||
-> ty::PolyTraitRef<'tcx>
|
||||
@ -732,6 +734,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||
param_mode,
|
||||
trait_def_id,
|
||||
None,
|
||||
trait_path_ref_id,
|
||||
trait_segment,
|
||||
projections)
|
||||
}
|
||||
@ -742,6 +745,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||
param_mode: PathParamMode,
|
||||
trait_def_id: DefId,
|
||||
self_ty: Option<Ty<'tcx>>,
|
||||
path_id: ast::NodeId,
|
||||
trait_segment: &hir::PathSegment,
|
||||
poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
|
||||
-> ty::PolyTraitRef<'tcx>
|
||||
@ -770,7 +774,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||
.filter_map(|binding| {
|
||||
// specify type to assert that error was already reported in Err case:
|
||||
let predicate: Result<_, ErrorReported> =
|
||||
self.ast_type_binding_to_poly_projection_predicate(poly_trait_ref.clone(),
|
||||
self.ast_type_binding_to_poly_projection_predicate(path_id,
|
||||
poly_trait_ref.clone(),
|
||||
self_ty,
|
||||
binding);
|
||||
predicate.ok() // ok to ignore Err() because ErrorReported (see above)
|
||||
@ -863,7 +868,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||
(self.tcx().mk_substs(substs), assoc_bindings)
|
||||
}
|
||||
|
||||
fn ast_type_binding_to_poly_projection_predicate(&self,
|
||||
fn ast_type_binding_to_poly_projection_predicate(
|
||||
&self,
|
||||
path_id: ast::NodeId,
|
||||
mut trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
self_ty: Option<Ty<'tcx>>,
|
||||
binding: &ConvertedBinding<'tcx>)
|
||||
@ -887,6 +894,36 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||
//
|
||||
// We want to produce `<B as SuperTrait<int>>::T == foo`.
|
||||
|
||||
// Find any late-bound regions declared in `ty` that are not
|
||||
// declared in the trait-ref. These are not wellformed.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
|
||||
// for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
|
||||
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(binding.ty));
|
||||
debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref);
|
||||
debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
|
||||
for br in late_bound_in_ty.difference(&late_bound_in_trait_ref) {
|
||||
let br_name = match *br {
|
||||
ty::BrNamed(_, name) => name,
|
||||
_ => {
|
||||
span_bug!(
|
||||
binding.span,
|
||||
"anonymous bound region {:?} in binding but not trait ref",
|
||||
br);
|
||||
}
|
||||
};
|
||||
tcx.sess.add_lint(
|
||||
lint::builtin::HR_LIFETIME_IN_ASSOC_TYPE,
|
||||
path_id,
|
||||
binding.span,
|
||||
format!("binding for associated type `{}` references lifetime `{}`, \
|
||||
which does not appear in the trait input types",
|
||||
binding.item_name, br_name));
|
||||
}
|
||||
|
||||
// Simple case: X is defined in the current trait.
|
||||
if self.trait_defines_associated_type_named(trait_ref.def_id(), binding.item_name) {
|
||||
return Ok(ty::Binder(ty::ProjectionPredicate { // <-------------------+
|
||||
@ -1012,6 +1049,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||
path.span,
|
||||
PathParamMode::Explicit,
|
||||
trait_def_id,
|
||||
ty.id,
|
||||
path.segments.last().unwrap(),
|
||||
&mut projection_bounds);
|
||||
Ok((trait_ref, projection_bounds))
|
||||
@ -1416,6 +1454,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||
param_mode: PathParamMode,
|
||||
def: Def,
|
||||
opt_self_ty: Option<Ty<'tcx>>,
|
||||
base_path_ref_id: ast::NodeId,
|
||||
base_segments: &[hir::PathSegment])
|
||||
-> Ty<'tcx> {
|
||||
let tcx = self.tcx();
|
||||
@ -1434,6 +1473,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||
span,
|
||||
param_mode,
|
||||
trait_def_id,
|
||||
base_path_ref_id,
|
||||
base_segments.last().unwrap(),
|
||||
&mut projection_bounds);
|
||||
|
||||
@ -1518,6 +1558,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||
param_mode: PathParamMode,
|
||||
mut def: Def,
|
||||
opt_self_ty: Option<Ty<'tcx>>,
|
||||
base_path_ref_id: ast::NodeId,
|
||||
base_segments: &[hir::PathSegment],
|
||||
assoc_segments: &[hir::PathSegment])
|
||||
-> (Ty<'tcx>, Def) {
|
||||
@ -1532,6 +1573,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||
param_mode,
|
||||
def,
|
||||
opt_self_ty,
|
||||
base_path_ref_id,
|
||||
base_segments);
|
||||
debug!("finish_resolving_def_to_ty: base_def_to_ty returned {:?}", ty);
|
||||
// If any associated type segments remain, attempt to resolve them.
|
||||
@ -1607,7 +1649,45 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||
}
|
||||
hir::TyBareFn(ref bf) => {
|
||||
require_c_abi_if_variadic(tcx, &bf.decl, bf.abi, ast_ty.span);
|
||||
tcx.mk_fn_ptr(self.ty_of_bare_fn(bf.unsafety, bf.abi, &bf.decl))
|
||||
let bare_fn_ty = self.ty_of_bare_fn(bf.unsafety, bf.abi, &bf.decl);
|
||||
|
||||
// Find any late-bound regions declared in return type that do
|
||||
// not appear in the arguments. These are not wellformed.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// for<'a> fn() -> &'a str <-- 'a is bad
|
||||
// for<'a> fn(&'a String) -> &'a str <-- 'a is ok
|
||||
//
|
||||
// Note that we do this check **here** and not in
|
||||
// `ty_of_bare_fn` because the latter is also used to make
|
||||
// the types for fn items, and we do not want to issue a
|
||||
// warning then. (Once we fix #32330, the regions we are
|
||||
// checking for here would be considered early bound
|
||||
// anyway.)
|
||||
let inputs = bare_fn_ty.sig.inputs();
|
||||
let late_bound_in_args = tcx.collect_constrained_late_bound_regions(&inputs);
|
||||
let output = bare_fn_ty.sig.output();
|
||||
let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(&output);
|
||||
for br in late_bound_in_ret.difference(&late_bound_in_args) {
|
||||
let br_name = match *br {
|
||||
ty::BrNamed(_, name) => name,
|
||||
_ => {
|
||||
span_bug!(
|
||||
bf.decl.output.span(),
|
||||
"anonymous bound region {:?} in return but not args",
|
||||
br);
|
||||
}
|
||||
};
|
||||
tcx.sess.add_lint(
|
||||
lint::builtin::HR_LIFETIME_IN_ASSOC_TYPE,
|
||||
ast_ty.id,
|
||||
ast_ty.span,
|
||||
format!("return type references lifetime `{}`, \
|
||||
which does not appear in the trait input types",
|
||||
br_name));
|
||||
}
|
||||
tcx.mk_fn_ptr(bare_fn_ty)
|
||||
}
|
||||
hir::TyPolyTraitRef(ref bounds) => {
|
||||
self.conv_ty_poly_trait_ref(rscope, ast_ty.span, bounds)
|
||||
@ -1635,6 +1715,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||
PathParamMode::Explicit,
|
||||
def,
|
||||
opt_self_ty,
|
||||
ast_ty.id,
|
||||
&path.segments[..base_ty_end],
|
||||
&path.segments[base_ty_end..]);
|
||||
|
||||
|
@ -3866,6 +3866,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
PathParamMode::Optional,
|
||||
def,
|
||||
opt_self_ty,
|
||||
node_id,
|
||||
&ty_segments[..base_ty_end],
|
||||
&ty_segments[base_ty_end..]);
|
||||
let item_segment = path.segments.last().unwrap();
|
||||
|
@ -568,7 +568,8 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||
|
||||
let (fty, explicit_self_category) =
|
||||
AstConv::ty_of_method(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)),
|
||||
sig, untransformed_rcvr_ty);
|
||||
sig,
|
||||
untransformed_rcvr_ty);
|
||||
|
||||
let def_id = ccx.tcx.map.local_def_id(id);
|
||||
let substs = mk_item_substs(ccx, &ty_generics);
|
||||
|
@ -180,7 +180,7 @@ impl error::Error for ExplicitBug {
|
||||
#[must_use]
|
||||
#[derive(Clone)]
|
||||
pub struct DiagnosticBuilder<'a> {
|
||||
emitter: &'a RefCell<Box<Emitter>>,
|
||||
handler: &'a Handler,
|
||||
level: Level,
|
||||
message: String,
|
||||
code: Option<String>,
|
||||
@ -204,8 +204,9 @@ impl<'a> DiagnosticBuilder<'a> {
|
||||
return;
|
||||
}
|
||||
|
||||
self.emitter.borrow_mut().emit_struct(&self);
|
||||
self.handler.emit.borrow_mut().emit_struct(&self);
|
||||
self.cancel();
|
||||
self.handler.panic_if_treat_err_as_bug();
|
||||
|
||||
// if self.is_fatal() {
|
||||
// panic!(FatalError);
|
||||
@ -321,11 +322,11 @@ impl<'a> DiagnosticBuilder<'a> {
|
||||
|
||||
/// Convenience function for internal use, clients should use one of the
|
||||
/// struct_* methods on Handler.
|
||||
fn new(emitter: &'a RefCell<Box<Emitter>>,
|
||||
fn new(handler: &'a Handler,
|
||||
level: Level,
|
||||
message: &str) -> DiagnosticBuilder<'a> {
|
||||
DiagnosticBuilder {
|
||||
emitter: emitter,
|
||||
handler: handler,
|
||||
level: level,
|
||||
message: message.to_owned(),
|
||||
code: None,
|
||||
@ -362,10 +363,10 @@ impl<'a> fmt::Debug for DiagnosticBuilder<'a> {
|
||||
impl<'a> Drop for DiagnosticBuilder<'a> {
|
||||
fn drop(&mut self) {
|
||||
if !panicking() && !self.cancelled() {
|
||||
self.emitter.borrow_mut().emit(&MultiSpan::new(),
|
||||
"Error constructed but not emitted",
|
||||
None,
|
||||
Bug);
|
||||
self.handler.emit.borrow_mut().emit(&MultiSpan::new(),
|
||||
"Error constructed but not emitted",
|
||||
None,
|
||||
Bug);
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
@ -412,14 +413,14 @@ impl Handler {
|
||||
}
|
||||
|
||||
pub fn struct_dummy<'a>(&'a self) -> DiagnosticBuilder<'a> {
|
||||
DiagnosticBuilder::new(&self.emit, Level::Cancelled, "")
|
||||
DiagnosticBuilder::new(self, Level::Cancelled, "")
|
||||
}
|
||||
|
||||
pub fn struct_span_warn<'a, S: Into<MultiSpan>>(&'a self,
|
||||
sp: S,
|
||||
msg: &str)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
let mut result = DiagnosticBuilder::new(&self.emit, Level::Warning, msg);
|
||||
let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
|
||||
result.set_span(sp);
|
||||
if !self.can_emit_warnings {
|
||||
result.cancel();
|
||||
@ -431,7 +432,7 @@ impl Handler {
|
||||
msg: &str,
|
||||
code: &str)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
let mut result = DiagnosticBuilder::new(&self.emit, Level::Warning, msg);
|
||||
let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
|
||||
result.set_span(sp);
|
||||
result.code(code.to_owned());
|
||||
if !self.can_emit_warnings {
|
||||
@ -440,7 +441,7 @@ impl Handler {
|
||||
result
|
||||
}
|
||||
pub fn struct_warn<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
|
||||
let mut result = DiagnosticBuilder::new(&self.emit, Level::Warning, msg);
|
||||
let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
|
||||
if !self.can_emit_warnings {
|
||||
result.cancel();
|
||||
}
|
||||
@ -451,7 +452,7 @@ impl Handler {
|
||||
msg: &str)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
self.bump_err_count();
|
||||
let mut result = DiagnosticBuilder::new(&self.emit, Level::Error, msg);
|
||||
let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
|
||||
result.set_span(sp);
|
||||
result
|
||||
}
|
||||
@ -461,21 +462,21 @@ impl Handler {
|
||||
code: &str)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
self.bump_err_count();
|
||||
let mut result = DiagnosticBuilder::new(&self.emit, Level::Error, msg);
|
||||
let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
|
||||
result.set_span(sp);
|
||||
result.code(code.to_owned());
|
||||
result
|
||||
}
|
||||
pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
|
||||
self.bump_err_count();
|
||||
DiagnosticBuilder::new(&self.emit, Level::Error, msg)
|
||||
DiagnosticBuilder::new(self, Level::Error, msg)
|
||||
}
|
||||
pub fn struct_span_fatal<'a, S: Into<MultiSpan>>(&'a self,
|
||||
sp: S,
|
||||
msg: &str)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
self.bump_err_count();
|
||||
let mut result = DiagnosticBuilder::new(&self.emit, Level::Fatal, msg);
|
||||
let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg);
|
||||
result.set_span(sp);
|
||||
result
|
||||
}
|
||||
@ -485,14 +486,14 @@ impl Handler {
|
||||
code: &str)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
self.bump_err_count();
|
||||
let mut result = DiagnosticBuilder::new(&self.emit, Level::Fatal, msg);
|
||||
let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg);
|
||||
result.set_span(sp);
|
||||
result.code(code.to_owned());
|
||||
result
|
||||
}
|
||||
pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
|
||||
self.bump_err_count();
|
||||
DiagnosticBuilder::new(&self.emit, Level::Fatal, msg)
|
||||
DiagnosticBuilder::new(self, Level::Fatal, msg)
|
||||
}
|
||||
|
||||
pub fn cancel(&mut self, err: &mut DiagnosticBuilder) {
|
||||
@ -503,36 +504,35 @@ impl Handler {
|
||||
err.cancel();
|
||||
}
|
||||
|
||||
pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> FatalError {
|
||||
fn panic_if_treat_err_as_bug(&self) {
|
||||
if self.treat_err_as_bug {
|
||||
self.span_bug(sp, msg);
|
||||
panic!("encountered error with `-Z treat_err_as_bug");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str)
|
||||
-> FatalError {
|
||||
self.emit(&sp.into(), msg, Fatal);
|
||||
self.bump_err_count();
|
||||
self.panic_if_treat_err_as_bug();
|
||||
return FatalError;
|
||||
}
|
||||
pub fn span_fatal_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str)
|
||||
-> FatalError {
|
||||
if self.treat_err_as_bug {
|
||||
self.span_bug(sp, msg);
|
||||
}
|
||||
-> FatalError {
|
||||
self.emit_with_code(&sp.into(), msg, code, Fatal);
|
||||
self.bump_err_count();
|
||||
self.panic_if_treat_err_as_bug();
|
||||
return FatalError;
|
||||
}
|
||||
pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
|
||||
if self.treat_err_as_bug {
|
||||
self.span_bug(sp, msg);
|
||||
}
|
||||
self.emit(&sp.into(), msg, Error);
|
||||
self.bump_err_count();
|
||||
self.panic_if_treat_err_as_bug();
|
||||
}
|
||||
pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) {
|
||||
if self.treat_err_as_bug {
|
||||
self.span_bug(sp, msg);
|
||||
}
|
||||
self.emit_with_code(&sp.into(), msg, code, Error);
|
||||
self.bump_err_count();
|
||||
self.panic_if_treat_err_as_bug();
|
||||
}
|
||||
pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
|
||||
self.emit(&sp.into(), msg, Warning);
|
||||
|
@ -40,6 +40,17 @@ impl<'a> TheTrait<&'a isize> for UintStruct {
|
||||
}
|
||||
}
|
||||
|
||||
struct Tuple {
|
||||
}
|
||||
|
||||
impl<'a> TheTrait<(&'a isize, &'a isize)> for Tuple {
|
||||
type A = &'a isize;
|
||||
|
||||
fn get(&self, t: (&'a isize, &'a isize)) -> &'a isize {
|
||||
t.0
|
||||
}
|
||||
}
|
||||
|
||||
fn foo<T>()
|
||||
where T : for<'x> TheTrait<&'x isize, A = &'x isize>
|
||||
{
|
||||
@ -52,10 +63,28 @@ fn bar<T>()
|
||||
// ok for UintStruct, but not IntStruct
|
||||
}
|
||||
|
||||
fn baz<T>()
|
||||
where T : for<'x,'y> TheTrait<&'x isize, A = &'y isize>
|
||||
fn tuple_one<T>()
|
||||
where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>
|
||||
{
|
||||
// not ok for either struct, due to the use of two lifetimes
|
||||
// not ok for tuple, two lifetimes and we pick first
|
||||
}
|
||||
|
||||
fn tuple_two<T>()
|
||||
where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>
|
||||
{
|
||||
// not ok for tuple, two lifetimes and we pick second
|
||||
}
|
||||
|
||||
fn tuple_three<T>()
|
||||
where T : for<'x> TheTrait<(&'x isize, &'x isize), A = &'x isize>
|
||||
{
|
||||
// ok for tuple
|
||||
}
|
||||
|
||||
fn tuple_four<T>()
|
||||
where T : for<'x,'y> TheTrait<(&'x isize, &'y isize)>
|
||||
{
|
||||
// not ok for tuple, two lifetimes, and lifetime matching is invariant
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
@ -65,6 +94,16 @@ pub fn main() {
|
||||
bar::<IntStruct>(); //~ ERROR type mismatch
|
||||
bar::<UintStruct>();
|
||||
|
||||
baz::<IntStruct>(); //~ ERROR type mismatch
|
||||
baz::<UintStruct>(); //~ ERROR type mismatch
|
||||
tuple_one::<Tuple>();
|
||||
//~^ ERROR E0277
|
||||
//~| ERROR type mismatch
|
||||
|
||||
tuple_two::<Tuple>();
|
||||
//~^ ERROR E0277
|
||||
//~| ERROR type mismatch
|
||||
|
||||
tuple_three::<Tuple>();
|
||||
|
||||
tuple_four::<Tuple>();
|
||||
//~^ ERROR E0277
|
||||
}
|
||||
|
@ -0,0 +1,66 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// revisions: func object clause
|
||||
|
||||
#![allow(dead_code)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![deny(hr_lifetime_in_assoc_type)]
|
||||
|
||||
trait Foo<'a> {
|
||||
type Item;
|
||||
}
|
||||
|
||||
impl<'a> Foo<'a> for() {
|
||||
type Item = ();
|
||||
}
|
||||
|
||||
// Check that appearing in a projection input in the argument is not enough:
|
||||
#[cfg(func)]
|
||||
fn func1(_: for<'a> fn(<() as Foo<'a>>::Item) -> &'a i32) {
|
||||
//[func]~^ ERROR return type references lifetime `'a`
|
||||
//[func]~| WARNING previously accepted
|
||||
}
|
||||
|
||||
// Check that appearing in a projection input in the return still
|
||||
// causes an error:
|
||||
#[cfg(func)]
|
||||
fn func2(_: for<'a> fn() -> <() as Foo<'a>>::Item) {
|
||||
//[func]~^ ERROR return type references lifetime `'a`
|
||||
//[func]~| WARNING previously accepted
|
||||
}
|
||||
|
||||
#[cfg(object)]
|
||||
fn object1(_: Box<for<'a> Fn(<() as Foo<'a>>::Item) -> &'a i32>) {
|
||||
//[object]~^ ERROR `Output` references lifetime `'a`
|
||||
//[object]~| WARNING previously accepted
|
||||
}
|
||||
|
||||
#[cfg(object)]
|
||||
fn object2(_: Box<for<'a> Fn() -> <() as Foo<'a>>::Item>) {
|
||||
//[object]~^ ERROR `Output` references lifetime `'a`
|
||||
//[object]~| WARNING previously accepted
|
||||
}
|
||||
|
||||
#[cfg(clause)]
|
||||
fn clause1<T>() where T: for<'a> Fn(<() as Foo<'a>>::Item) -> &'a i32 {
|
||||
//[clause]~^ ERROR `Output` references lifetime `'a`
|
||||
//[clause]~| WARNING previously accepted
|
||||
}
|
||||
|
||||
#[cfg(clause)]
|
||||
fn clause2<T>() where T: for<'a> Fn() -> <() as Foo<'a>>::Item {
|
||||
//[clause]~^ ERROR `Output` references lifetime `'a`
|
||||
//[clause]~| WARNING previously accepted
|
||||
}
|
||||
|
||||
#[rustc_error]
|
||||
fn main() { } //[ok]~ ERROR compilation successful
|
@ -0,0 +1,90 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// revisions: angle paren ok elision
|
||||
|
||||
#![allow(dead_code)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![deny(hr_lifetime_in_assoc_type)]
|
||||
|
||||
trait Foo {
|
||||
type Item;
|
||||
}
|
||||
|
||||
#[cfg(angle)]
|
||||
fn angle<T: for<'a> Foo<Item=&'a i32>>() {
|
||||
//[angle]~^ ERROR binding for associated type `Item` references lifetime `'a`
|
||||
//[angle]~| WARNING previously accepted
|
||||
}
|
||||
|
||||
#[cfg(angle)]
|
||||
fn angle1<T>() where T: for<'a> Foo<Item=&'a i32> {
|
||||
//[angle]~^ ERROR binding for associated type `Item` references lifetime `'a`
|
||||
//[angle]~| WARNING previously accepted
|
||||
}
|
||||
|
||||
#[cfg(angle)]
|
||||
fn angle2<T>() where for<'a> T: Foo<Item=&'a i32> {
|
||||
//[angle]~^ ERROR binding for associated type `Item` references lifetime `'a`
|
||||
//[angle]~| WARNING previously accepted
|
||||
}
|
||||
|
||||
#[cfg(angle)]
|
||||
fn angle3(_: &for<'a> Foo<Item=&'a i32>) {
|
||||
//[angle]~^ ERROR binding for associated type `Item` references lifetime `'a`
|
||||
//[angle]~| WARNING previously accepted
|
||||
}
|
||||
|
||||
#[cfg(paren)]
|
||||
fn paren<T: for<'a> Fn() -> &'a i32>() {
|
||||
//[paren]~^ ERROR binding for associated type `Output` references lifetime `'a`
|
||||
//[paren]~| WARNING previously accepted
|
||||
}
|
||||
|
||||
#[cfg(paren)]
|
||||
fn paren1<T>() where T: for<'a> Fn() -> &'a i32 {
|
||||
//[paren]~^ ERROR binding for associated type `Output` references lifetime `'a`
|
||||
//[paren]~| WARNING previously accepted
|
||||
}
|
||||
|
||||
#[cfg(paren)]
|
||||
fn paren2<T>() where for<'a> T: Fn() -> &'a i32 {
|
||||
//[paren]~^ ERROR binding for associated type `Output` references lifetime `'a`
|
||||
//[paren]~| WARNING previously accepted
|
||||
}
|
||||
|
||||
#[cfg(paren)]
|
||||
fn paren3(_: &for<'a> Fn() -> &'a i32) {
|
||||
//[paren]~^ ERROR binding for associated type `Output` references lifetime `'a`
|
||||
//[paren]~| WARNING previously accepted
|
||||
}
|
||||
|
||||
#[cfg(elision)]
|
||||
fn elision<T: Fn() -> &i32>() {
|
||||
//[elision]~^ ERROR E0106
|
||||
}
|
||||
|
||||
struct Parameterized<'a> { x: &'a str }
|
||||
|
||||
#[cfg(ok)]
|
||||
fn ok1<T: for<'a> Fn(&Parameterized<'a>) -> &'a i32>() {
|
||||
}
|
||||
|
||||
#[cfg(ok)]
|
||||
fn ok2<T: for<'a,'b> Fn<(&'b Parameterized<'a>,), Output=&'a i32>>() {
|
||||
}
|
||||
|
||||
#[cfg(ok)]
|
||||
fn ok3<T>() where for<'a> Parameterized<'a>: Foo<Item=&'a i32> {
|
||||
}
|
||||
|
||||
#[rustc_error]
|
||||
fn main() { } //[ok]~ ERROR compilation successful
|
@ -0,0 +1,64 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// revisions: sig local structure ok elision
|
||||
|
||||
#![allow(dead_code)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![deny(hr_lifetime_in_assoc_type)]
|
||||
|
||||
trait Foo {
|
||||
type Item;
|
||||
}
|
||||
|
||||
#[cfg(sig)]
|
||||
fn sig1(_: for<'a> fn() -> &'a i32) {
|
||||
//[sig]~^ ERROR return type references lifetime `'a`
|
||||
//[sig]~| WARNING previously accepted
|
||||
}
|
||||
|
||||
#[cfg(sig)]
|
||||
fn sig2(_: for<'a, 'b> fn(&'b i32) -> &'a i32) {
|
||||
//[sig]~^ ERROR return type references lifetime `'a`
|
||||
//[sig]~| WARNING previously accepted
|
||||
}
|
||||
|
||||
#[cfg(local)]
|
||||
fn local1() {
|
||||
let _: for<'a> fn() -> &'a i32 = loop { };
|
||||
//[local]~^ ERROR return type references lifetime `'a`
|
||||
//[local]~| WARNING previously accepted
|
||||
}
|
||||
|
||||
#[cfg(structure)]
|
||||
struct Struct1 {
|
||||
x: for<'a> fn() -> &'a i32
|
||||
//[structure]~^ ERROR return type references lifetime `'a`
|
||||
//[structure]~| WARNING previously accepted
|
||||
}
|
||||
|
||||
#[cfg(elision)]
|
||||
fn elision(_: fn() -> &i32) {
|
||||
//[elision]~^ ERROR E0106
|
||||
}
|
||||
|
||||
struct Parameterized<'a> { x: &'a str }
|
||||
|
||||
#[cfg(ok)]
|
||||
fn ok1(_: &for<'a> Fn(&Parameterized<'a>) -> &'a i32) {
|
||||
}
|
||||
|
||||
#[cfg(ok)]
|
||||
fn ok2(_: &for<'a,'b> Fn<(&'b Parameterized<'a>,), Output=&'a i32>) {
|
||||
}
|
||||
|
||||
#[rustc_error]
|
||||
fn main() { } //[ok]~ ERROR compilation successful
|
Loading…
x
Reference in New Issue
Block a user