diff options
| author | Alex Crichton <alex@alexcrichton.com> | 2018-03-23 09:27:16 -0500 |
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2018-03-23 10:16:08 -0700 |
| commit | 7c0c7ef330fd87e8b169f0afc832d15bf098d0f0 (patch) | |
| tree | ddd4d8c545630c041e2f91ef72bdc4913ccdcd58 | |
| parent | f836ae48e6e0b55af1d0d6cd579424f26314d530 (diff) | |
| parent | c05d23406ead7b5747256c02127097807db45b83 (diff) | |
| download | rust-7c0c7ef330fd87e8b169f0afc832d15bf098d0f0.tar.gz rust-7c0c7ef330fd87e8b169f0afc832d15bf098d0f0.zip | |
Rollup merge of #48909 - RalfJung:type_alias_bounds, r=petrochenkov
Improve lint for type alias bounds First of all, I learned just today that I was wrong assuming that the bounds in type aliases are entirely ignored: It turns out they are used to resolve associated types in type aliases. So: ```rust type T1<U: Bound> = U::Assoc; // compiles type T2<U> = U::Assoc; // fails type T3<U> = <U as Bound>::Assoc; // "correct" way to write this, maybe? ``` I am sorry for creating this mess. This PR changes the wording of the lint accordingly. Moreover, since just removing the bound is no longer always a possible fix, I tried to detect cases like `T1` above and show a helpful message to the user: ``` warning: bounds on generic parameters are not enforced in type aliases --> $DIR/type-alias-bounds.rs:57:12 | LL | type T1<U: Bound> = U::Assoc; //~ WARN not enforced in type aliases | ^^^^^ | = help: the bound will not be checked when the type alias is used, and should be removed help: use absolute paths (i.e., <T as Trait>::Assoc) to refer to associated types in type aliases --> $DIR/type-alias-bounds.rs:57:21 | LL | type T1<U: Bound> = U::Assoc; //~ WARN not enforced in type aliases | ^^^^^^^^ ``` I am not sure if I got this entirely right. Ideally, we could provide a suggestion involving the correct trait and type name -- however, while I have access to the HIR in the lint, I do not know how to get access to the resolved name information, like which trait `Assoc` belongs to above. The lint does not even run if that resolution fails, so I assume that information is available *somewhere*... This is a follow-up for (parts of) https://github.com/rust-lang/rust/pull/48326. Also see https://github.com/rust-lang/rust/issues/21903. This changes the name of a lint, but that lint was just merged to master yesterday and has never even been on beta.
| -rw-r--r-- | src/librustc/hir/mod.rs | 19 | ||||
| -rw-r--r-- | src/librustc_lint/builtin.rs | 104 | ||||
| -rw-r--r-- | src/librustc_lint/lib.rs | 2 | ||||
| -rw-r--r-- | src/test/compile-fail/issue-17994.rs | 1 | ||||
| -rw-r--r-- | src/test/compile-fail/private-in-public-warn.rs | 2 | ||||
| -rw-r--r-- | src/test/ui/higher-lifetime-bounds.rs (renamed from src/test/ui/param-bounds-ignored.rs) | 26 | ||||
| -rw-r--r-- | src/test/ui/higher-lifetime-bounds.stderr (renamed from src/test/ui/param-bounds-ignored.stderr) | 48 | ||||
| -rw-r--r-- | src/test/ui/type-alias-bounds.rs | 69 | ||||
| -rw-r--r-- | src/test/ui/type-alias-bounds.stderr | 83 |
9 files changed, 270 insertions, 84 deletions
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index d6810b2468b..12b472a7285 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -395,6 +395,15 @@ pub enum TyParamBound { RegionTyParamBound(Lifetime), } +impl TyParamBound { + pub fn span(&self) -> Span { + match self { + &TraitTyParamBound(ref t, ..) => t.span, + &RegionTyParamBound(ref l) => l.span, + } + } +} + /// A modifier on a bound, currently this is only used for `?Sized`, where the /// modifier is `Maybe`. Negative bounds should also be handled here. #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] @@ -571,6 +580,16 @@ pub enum WherePredicate { EqPredicate(WhereEqPredicate), } +impl WherePredicate { + pub fn span(&self) -> Span { + match self { + &WherePredicate::BoundPredicate(ref p) => p.span, + &WherePredicate::RegionPredicate(ref p) => p.span, + &WherePredicate::EqPredicate(ref p) => p.span, + } + } +} + /// A type bound, eg `for<'c> Foo: Send+Clone+'c` #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct WhereBoundPredicate { diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index bffa8628ff3..c0728cb2b66 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -46,6 +46,7 @@ use syntax::attr; use syntax::feature_gate::{AttributeGate, AttributeType, Stability, deprecated_attributes}; use syntax_pos::{BytePos, Span, SyntaxContext}; use syntax::symbol::keywords; +use syntax::errors::DiagnosticBuilder; use rustc::hir::{self, PatKind}; use rustc::hir::intravisit::FnKind; @@ -1316,48 +1317,115 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnreachablePub { } } -/// Lint for trait and lifetime bounds that are (accidentally) accepted by the parser, but -/// ignored later. +/// Lint for trait and lifetime bounds in type aliases being mostly ignored: +/// They are relevant when using associated types, but otherwise neither checked +/// at definition site nor enforced at use site. -pub struct IgnoredGenericBounds; +pub struct TypeAliasBounds; declare_lint! { - IGNORED_GENERIC_BOUNDS, + TYPE_ALIAS_BOUNDS, Warn, - "these generic bounds are ignored" + "bounds in type aliases are not enforced" } -impl LintPass for IgnoredGenericBounds { +impl LintPass for TypeAliasBounds { fn get_lints(&self) -> LintArray { - lint_array!(IGNORED_GENERIC_BOUNDS) + lint_array!(TYPE_ALIAS_BOUNDS) } } -impl EarlyLintPass for IgnoredGenericBounds { - fn check_item(&mut self, cx: &EarlyContext, item: &ast::Item) { - let type_alias_generics = match item.node { - ast::ItemKind::Ty(_, ref generics) => generics, +impl TypeAliasBounds { + fn is_type_variable_assoc(qpath: &hir::QPath) -> bool { + match *qpath { + hir::QPath::TypeRelative(ref ty, _) => { + // If this is a type variable, we found a `T::Assoc`. + match ty.node { + hir::TyPath(hir::QPath::Resolved(None, ref path)) => { + match path.def { + Def::TyParam(_) => true, + _ => false + } + } + _ => false + } + } + hir::QPath::Resolved(..) => false, + } + } + + fn suggest_changing_assoc_types(ty: &hir::Ty, err: &mut DiagnosticBuilder) { + // Access to associates types should use `<T as Bound>::Assoc`, which does not need a + // bound. Let's see if this type does that. + + // We use a HIR visitor to walk the type. + use rustc::hir::intravisit::{self, Visitor}; + use syntax::ast::NodeId; + struct WalkAssocTypes<'a, 'db> where 'db: 'a { + err: &'a mut DiagnosticBuilder<'db> + } + impl<'a, 'db, 'v> Visitor<'v> for WalkAssocTypes<'a, 'db> { + fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'v> + { + intravisit::NestedVisitorMap::None + } + + fn visit_qpath(&mut self, qpath: &'v hir::QPath, id: NodeId, span: Span) { + if TypeAliasBounds::is_type_variable_assoc(qpath) { + self.err.span_help(span, + "use fully disambiguated paths (i.e., `<T as Trait>::Assoc`) to refer to \ + associated types in type aliases"); + } + intravisit::walk_qpath(self, qpath, id, span) + } + } + + // Let's go for a walk! + let mut visitor = WalkAssocTypes { err }; + visitor.visit_ty(ty); + } +} + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeAliasBounds { + fn check_item(&mut self, cx: &LateContext, item: &hir::Item) { + let (ty, type_alias_generics) = match item.node { + hir::ItemTy(ref ty, ref generics) => (&*ty, generics), _ => return, }; + let mut suggested_changing_assoc_types = false; // There must not be a where clause if !type_alias_generics.where_clause.predicates.is_empty() { let spans : Vec<_> = type_alias_generics.where_clause.predicates.iter() .map(|pred| pred.span()).collect(); - cx.span_lint(IGNORED_GENERIC_BOUNDS, spans, - "where clauses are ignored in type aliases"); + let mut err = cx.struct_span_lint(TYPE_ALIAS_BOUNDS, spans, + "where clauses are not enforced in type aliases"); + err.help("the clause will not be checked when the type alias is used, \ + and should be removed"); + if !suggested_changing_assoc_types { + TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err); + suggested_changing_assoc_types = true; + } + err.emit(); } // The parameters must not have bounds for param in type_alias_generics.params.iter() { let spans : Vec<_> = match param { - &ast::GenericParam::Lifetime(ref l) => l.bounds.iter().map(|b| b.span).collect(), - &ast::GenericParam::Type(ref ty) => ty.bounds.iter().map(|b| b.span()).collect(), + &hir::GenericParam::Lifetime(ref l) => l.bounds.iter().map(|b| b.span).collect(), + &hir::GenericParam::Type(ref ty) => ty.bounds.iter().map(|b| b.span()).collect(), }; if !spans.is_empty() { - cx.span_lint( - IGNORED_GENERIC_BOUNDS, + let mut err = cx.struct_span_lint( + TYPE_ALIAS_BOUNDS, spans, - "bounds on generic parameters are ignored in type aliases", + "bounds on generic parameters are not enforced in type aliases", ); + err.help("the bound will not be checked when the type alias is used, \ + and should be removed"); + if !suggested_changing_assoc_types { + TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err); + suggested_changing_assoc_types = true; + } + err.emit(); } } } diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index ce896bfb701..30dd2efeb7a 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -109,7 +109,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { UnusedImportBraces, AnonymousParameters, UnusedDocComment, - IgnoredGenericBounds, ); add_early_builtin_with_new!(sess, @@ -139,6 +138,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { MutableTransmutes, UnionsWithDropFields, UnreachablePub, + TypeAliasBounds, ); add_builtin_with_new!(sess, diff --git a/src/test/compile-fail/issue-17994.rs b/src/test/compile-fail/issue-17994.rs index 0f30e2461cf..25141b9b825 100644 --- a/src/test/compile-fail/issue-17994.rs +++ b/src/test/compile-fail/issue-17994.rs @@ -10,5 +10,4 @@ trait Tr {} type Huh<T> where T: Tr = isize; //~ ERROR type parameter `T` is unused - //~| WARNING where clauses are ignored in type aliases fn main() {} diff --git a/src/test/compile-fail/private-in-public-warn.rs b/src/test/compile-fail/private-in-public-warn.rs index cc9eed7e654..6eeb14638e7 100644 --- a/src/test/compile-fail/private-in-public-warn.rs +++ b/src/test/compile-fail/private-in-public-warn.rs @@ -58,7 +58,6 @@ mod traits { pub trait PubTr {} pub type Alias<T: PrivTr> = T; //~ ERROR private trait `traits::PrivTr` in public interface - //~^ WARNING bounds on generic parameters are ignored //~| WARNING hard error pub trait Tr1: PrivTr {} //~ ERROR private trait `traits::PrivTr` in public interface //~^ WARNING hard error @@ -85,7 +84,6 @@ mod traits_where { pub type Alias<T> where T: PrivTr = T; //~^ ERROR private trait `traits_where::PrivTr` in public interface //~| WARNING hard error - //~| WARNING where clauses are ignored in type aliases pub trait Tr2<T> where T: PrivTr {} //~^ ERROR private trait `traits_where::PrivTr` in public interface //~| WARNING hard error diff --git a/src/test/ui/param-bounds-ignored.rs b/src/test/ui/higher-lifetime-bounds.rs index 94bcdec9450..70b3b34fbd8 100644 --- a/src/test/ui/param-bounds-ignored.rs +++ b/src/test/ui/higher-lifetime-bounds.rs @@ -10,31 +10,7 @@ #![allow(dead_code, non_camel_case_types)] -use std::rc::Rc; - -type SVec<T: Send+Send> = Vec<T>; -//~^ WARN bounds on generic parameters are ignored in type aliases -type VVec<'b, 'a: 'b+'b> = Vec<&'a i32>; -//~^ WARN bounds on generic parameters are ignored in type aliases -type WVec<'b, T: 'b+'b> = Vec<T>; -//~^ WARN bounds on generic parameters are ignored in type aliases -type W2Vec<'b, T> where T: 'b, T: 'b = Vec<T>; -//~^ WARN where clauses are ignored in type aliases - -fn foo<'a>(y: &'a i32) { - // If the bounds above would matter, the code below would be rejected. - let mut x : SVec<_> = Vec::new(); - x.push(Rc::new(42)); - - let mut x : VVec<'static, 'a> = Vec::new(); - x.push(y); - - let mut x : WVec<'static, & 'a i32> = Vec::new(); - x.push(y); - - let mut x : W2Vec<'static, & 'a i32> = Vec::new(); - x.push(y); -} +// Test that bounds on higher-kinded lifetime binders are rejected. fn bar1<'a, 'b>( x: &'a i32, diff --git a/src/test/ui/param-bounds-ignored.stderr b/src/test/ui/higher-lifetime-bounds.stderr index 657fec54f96..82c00747436 100644 --- a/src/test/ui/param-bounds-ignored.stderr +++ b/src/test/ui/higher-lifetime-bounds.stderr @@ -1,94 +1,68 @@ error: lifetime bounds cannot be used in this context - --> $DIR/param-bounds-ignored.rs:42:22 + --> $DIR/higher-lifetime-bounds.rs:18:22 | LL | f: for<'xa, 'xb: 'xa+'xa> fn(&'xa i32, &'xb i32) -> &'xa i32) | ^^^ ^^^ error: lifetime bounds cannot be used in this context - --> $DIR/param-bounds-ignored.rs:50:34 + --> $DIR/higher-lifetime-bounds.rs:26:34 | LL | fn bar2<'a, 'b, F: for<'xa, 'xb: 'xa> Fn(&'xa i32, &'xb i32) -> &'xa i32>( | ^^^ error: lifetime bounds cannot be used in this context - --> $DIR/param-bounds-ignored.rs:65:28 + --> $DIR/higher-lifetime-bounds.rs:41:28 | LL | where F: for<'xa, 'xb: 'xa> Fn(&'xa i32, &'xb i32) -> &'xa i32 | ^^^ error: lifetime bounds cannot be used in this context - --> $DIR/param-bounds-ignored.rs:77:25 + --> $DIR/higher-lifetime-bounds.rs:53:25 | LL | where for<'xa, 'xb: 'xa> F: Fn(&'xa i32, &'xb i32) -> &'xa i32 | ^^^ error: lifetime bounds cannot be used in this context - --> $DIR/param-bounds-ignored.rs:85:28 + --> $DIR/higher-lifetime-bounds.rs:61:28 | LL | struct S1<F: for<'xa, 'xb: 'xa> Fn(&'xa i32, &'xb i32) -> &'xa i32>(F); | ^^^ error: lifetime bounds cannot be used in this context - --> $DIR/param-bounds-ignored.rs:87:40 + --> $DIR/higher-lifetime-bounds.rs:63:40 | LL | struct S2<F>(F) where F: for<'xa, 'xb: 'xa> Fn(&'xa i32, &'xb i32) -> &'xa i32; | ^^^ error: lifetime bounds cannot be used in this context - --> $DIR/param-bounds-ignored.rs:89:37 + --> $DIR/higher-lifetime-bounds.rs:65:37 | LL | struct S3<F>(F) where for<'xa, 'xb: 'xa> F: Fn(&'xa i32, &'xb i32) -> &'xa i32; | ^^^ error: lifetime bounds cannot be used in this context - --> $DIR/param-bounds-ignored.rs:92:29 + --> $DIR/higher-lifetime-bounds.rs:68:29 | LL | struct S_fnty(for<'xa, 'xb: 'xa> fn(&'xa i32, &'xb i32) -> &'xa i32); | ^^^ error: lifetime bounds cannot be used in this context - --> $DIR/param-bounds-ignored.rs:95:29 + --> $DIR/higher-lifetime-bounds.rs:71:29 | LL | type T1 = Box<for<'xa, 'xb: 'xa> Fn(&'xa i32, &'xb i32) -> &'xa i32>; | ^^^ error: lifetime bounds cannot be used in this context - --> $DIR/param-bounds-ignored.rs:99:34 + --> $DIR/higher-lifetime-bounds.rs:75:34 | LL | let _ : Option<for<'xa, 'xb: 'xa> fn(&'xa i32, &'xb i32) -> &'xa i32> = None; | ^^^ error: lifetime bounds cannot be used in this context - --> $DIR/param-bounds-ignored.rs:101:38 + --> $DIR/higher-lifetime-bounds.rs:77:38 | LL | let _ : Option<Box<for<'xa, 'xb: 'xa> Fn(&'xa i32, &'xb i32) -> &'xa i32>> = None; | ^^^ -warning: bounds on generic parameters are ignored in type aliases - --> $DIR/param-bounds-ignored.rs:15:14 - | -LL | type SVec<T: Send+Send> = Vec<T>; - | ^^^^ ^^^^ - | - = note: #[warn(ignored_generic_bounds)] on by default - -warning: bounds on generic parameters are ignored in type aliases - --> $DIR/param-bounds-ignored.rs:17:19 - | -LL | type VVec<'b, 'a: 'b+'b> = Vec<&'a i32>; - | ^^ ^^ - -warning: bounds on generic parameters are ignored in type aliases - --> $DIR/param-bounds-ignored.rs:19:18 - | -LL | type WVec<'b, T: 'b+'b> = Vec<T>; - | ^^ ^^ - -warning: where clauses are ignored in type aliases - --> $DIR/param-bounds-ignored.rs:21:25 - | -LL | type W2Vec<'b, T> where T: 'b, T: 'b = Vec<T>; - | ^^^^^ ^^^^^ - error: aborting due to 11 previous errors diff --git a/src/test/ui/type-alias-bounds.rs b/src/test/ui/type-alias-bounds.rs new file mode 100644 index 00000000000..c1cdeef3a46 --- /dev/null +++ b/src/test/ui/type-alias-bounds.rs @@ -0,0 +1,69 @@ +// Copyright 2014 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. + +// Test ignored_generic_bounds lint warning about bounds in type aliases + +// must-compile-successfully +#![allow(dead_code)] + +use std::rc::Rc; + +type SVec<T: Send+Send> = Vec<T>; +//~^ WARN bounds on generic parameters are not enforced in type aliases [type_alias_bounds] +type S2Vec<T> where T: Send = Vec<T>; +//~^ WARN where clauses are not enforced in type aliases [type_alias_bounds] +type VVec<'b, 'a: 'b+'b> = (&'b u32, Vec<&'a i32>); +//~^ WARN bounds on generic parameters are not enforced in type aliases [type_alias_bounds] +type WVec<'b, T: 'b+'b> = (&'b u32, Vec<T>); +//~^ WARN bounds on generic parameters are not enforced in type aliases [type_alias_bounds] +type W2Vec<'b, T> where T: 'b, T: 'b = (&'b u32, Vec<T>); +//~^ WARN where clauses are not enforced in type aliases [type_alias_bounds] + +static STATIC : u32 = 0; + +fn foo<'a>(y: &'a i32) { + // If any of the bounds above would matter, the code below would be rejected. + // This can be seen when replacing the type aliases above by newtype structs. + // (The type aliases have no unused parameters to make that a valid transformation.) + let mut x : SVec<_> = Vec::new(); + x.push(Rc::new(42)); // is not send + + let mut x : S2Vec<_> = Vec::new(); + x.push(Rc::new(42)); // is not send + + let mut x : VVec<'static, 'a> = (&STATIC, Vec::new()); + x.1.push(y); // 'a: 'static does not hold + + let mut x : WVec<'static, &'a i32> = (&STATIC, Vec::new()); + x.1.push(y); // &'a i32: 'static does not hold + + let mut x : W2Vec<'static, &'a i32> = (&STATIC, Vec::new()); + x.1.push(y); // &'a i32: 'static does not hold +} + +// Bounds are not checked either, i.e. the definition is not necessarily well-formed +struct Sendable<T: Send>(T); +type MySendable<T> = Sendable<T>; // no error here! + +// However, bounds *are* taken into account when accessing associated types +trait Bound { type Assoc; } +type T1<U: Bound> = U::Assoc; //~ WARN not enforced in type aliases +type T2<U> where U: Bound = U::Assoc; //~ WARN not enforced in type aliases + +// This errors +// type T3<U> = U::Assoc; +// Do this instead +type T4<U> = <U as Bound>::Assoc; + +// Make sure the help about associatd types is not shown incorrectly +type T5<U: Bound> = <U as Bound>::Assoc; //~ WARN not enforced in type aliases +type T6<U: Bound> = ::std::vec::Vec<U>; //~ WARN not enforced in type aliases + +fn main() {} diff --git a/src/test/ui/type-alias-bounds.stderr b/src/test/ui/type-alias-bounds.stderr new file mode 100644 index 00000000000..2a2b0b0f26e --- /dev/null +++ b/src/test/ui/type-alias-bounds.stderr @@ -0,0 +1,83 @@ +warning: bounds on generic parameters are not enforced in type aliases + --> $DIR/type-alias-bounds.rs:18:14 + | +LL | type SVec<T: Send+Send> = Vec<T>; + | ^^^^ ^^^^ + | + = note: #[warn(type_alias_bounds)] on by default + = help: the bound will not be checked when the type alias is used, and should be removed + +warning: where clauses are not enforced in type aliases + --> $DIR/type-alias-bounds.rs:20:21 + | +LL | type S2Vec<T> where T: Send = Vec<T>; + | ^^^^^^^ + | + = help: the clause will not be checked when the type alias is used, and should be removed + +warning: bounds on generic parameters are not enforced in type aliases + --> $DIR/type-alias-bounds.rs:22:19 + | +LL | type VVec<'b, 'a: 'b+'b> = (&'b u32, Vec<&'a i32>); + | ^^ ^^ + | + = help: the bound will not be checked when the type alias is used, and should be removed + +warning: bounds on generic parameters are not enforced in type aliases + --> $DIR/type-alias-bounds.rs:24:18 + | +LL | type WVec<'b, T: 'b+'b> = (&'b u32, Vec<T>); + | ^^ ^^ + | + = help: the bound will not be checked when the type alias is used, and should be removed + +warning: where clauses are not enforced in type aliases + --> $DIR/type-alias-bounds.rs:26:25 + | +LL | type W2Vec<'b, T> where T: 'b, T: 'b = (&'b u32, Vec<T>); + | ^^^^^ ^^^^^ + | + = help: the clause will not be checked when the type alias is used, and should be removed + +warning: bounds on generic parameters are not enforced in type aliases + --> $DIR/type-alias-bounds.rs:57:12 + | +LL | type T1<U: Bound> = U::Assoc; //~ WARN not enforced in type aliases + | ^^^^^ + | + = help: the bound will not be checked when the type alias is used, and should be removed +help: use fully disambiguated paths (i.e., `<T as Trait>::Assoc`) to refer to associated types in type aliases + --> $DIR/type-alias-bounds.rs:57:21 + | +LL | type T1<U: Bound> = U::Assoc; //~ WARN not enforced in type aliases + | ^^^^^^^^ + +warning: where clauses are not enforced in type aliases + --> $DIR/type-alias-bounds.rs:58:18 + | +LL | type T2<U> where U: Bound = U::Assoc; //~ WARN not enforced in type aliases + | ^^^^^^^^ + | + = help: the clause will not be checked when the type alias is used, and should be removed +help: use fully disambiguated paths (i.e., `<T as Trait>::Assoc`) to refer to associated types in type aliases + --> $DIR/type-alias-bounds.rs:58:29 + | +LL | type T2<U> where U: Bound = U::Assoc; //~ WARN not enforced in type aliases + | ^^^^^^^^ + +warning: bounds on generic parameters are not enforced in type aliases + --> $DIR/type-alias-bounds.rs:66:12 + | +LL | type T5<U: Bound> = <U as Bound>::Assoc; //~ WARN not enforced in type aliases + | ^^^^^ + | + = help: the bound will not be checked when the type alias is used, and should be removed + +warning: bounds on generic parameters are not enforced in type aliases + --> $DIR/type-alias-bounds.rs:67:12 + | +LL | type T6<U: Bound> = ::std::vec::Vec<U>; //~ WARN not enforced in type aliases + | ^^^^^ + | + = help: the bound will not be checked when the type alias is used, and should be removed + |
