Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue warnings for late-bound regions in assoc type bindings and output types #32488

10 changes: 9 additions & 1 deletion src/librustc/lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -213,7 +220,8 @@ impl LintPass for HardwiredLints {
RAW_POINTER_DERIVE,
TRANSMUTE_FROM_FN_ITEM_TYPES,
OVERLAPPING_INHERENT_IMPLS,
RENAMED_AND_REMOVED_LINTS
RENAMED_AND_REMOVED_LINTS,
HR_LIFETIME_IN_ASSOC_TYPE
)
}
}
Expand Down
469 changes: 281 additions & 188 deletions src/librustc/traits/project.rs

Large diffs are not rendered by default.

9 changes: 7 additions & 2 deletions src/librustc/ty/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,13 @@ impl FlagComputation {

fn add_region(&mut self, r: ty::Region) {
match r {
ty::ReVar(..) |
ty::ReSkolemized(..) => { self.add_flags(TypeFlags::HAS_RE_INFER); }
ty::ReVar(..) => {
self.add_flags(TypeFlags::HAS_RE_INFER);
}
ty::ReSkolemized(..) => {
self.add_flags(TypeFlags::HAS_RE_INFER);
self.add_flags(TypeFlags::HAS_RE_SKOL);
}
ty::ReLateBound(debruijn, _) => { self.add_depth(debruijn.depth); }
ty::ReEarlyBound(..) => { self.add_flags(TypeFlags::HAS_RE_EARLY_BOUND); }
ty::ReStatic => {}
Expand Down
81 changes: 81 additions & 0 deletions src/librustc/ty/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,35 @@ impl<'tcx> TyCtxt<'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
Expand Down Expand Up @@ -640,3 +669,55 @@ 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 enter_region_binder(&mut self) {
self.current_depth += 1;
}

fn exit_region_binder(&mut self) {
self.current_depth -= 1;
}

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
}
}

13 changes: 7 additions & 6 deletions src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -475,15 +475,16 @@ bitflags! {
const HAS_SELF = 1 << 1,
const HAS_TY_INFER = 1 << 2,
const HAS_RE_INFER = 1 << 3,
const HAS_RE_EARLY_BOUND = 1 << 4,
const HAS_FREE_REGIONS = 1 << 5,
const HAS_TY_ERR = 1 << 6,
const HAS_PROJECTION = 1 << 7,
const HAS_TY_CLOSURE = 1 << 8,
const HAS_RE_SKOL = 1 << 4,
const HAS_RE_EARLY_BOUND = 1 << 5,
const HAS_FREE_REGIONS = 1 << 6,
const HAS_TY_ERR = 1 << 7,
const HAS_PROJECTION = 1 << 8,
const HAS_TY_CLOSURE = 1 << 9,

// true if there are "names" of types and regions and so forth
// that are local to a particular fn
const HAS_LOCAL_NAMES = 1 << 9,
const HAS_LOCAL_NAMES = 1 << 10,

const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits |
TypeFlags::HAS_SELF.bits |
Expand Down
4 changes: 4 additions & 0 deletions src/librustc_lint/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
id: LintId::of(ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN),
reference: "RFC 1445 <https://github.com/rust-lang/rfcs/pull/1445>",
},
FutureIncompatibleInfo {
id: LintId::of(HR_LIFETIME_IN_ASSOC_TYPE),
reference: "issue #32330 <https://github.com/rust-lang/rust/issues/32330>",
},
]);

// We have one lint pass defined specially
Expand Down
Loading