Skip to content

Commit

Permalink
ANN: Update inspections for Type Aliases
Browse files Browse the repository at this point in the history
  • Loading branch information
mchernyavsky committed Nov 24, 2021
1 parent bec15e3 commit b7b35c0
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 33 deletions.
35 changes: 31 additions & 4 deletions src/main/kotlin/org/rust/ide/annotator/RsErrorAnnotator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,7 @@ class RsErrorAnnotator : AnnotatorBase(), HighlightRangeExtension {
if (parent is RsImplItem ||
parent is RsForeignModItem ||
parent is RsEnumVariant ||
isInTrait(vis) ||
isInTraitImpl(vis) ||
isInEnumVariantField(vis)
) {
Expand Down Expand Up @@ -948,6 +949,31 @@ class RsErrorAnnotator : AnnotatorBase(), HighlightRangeExtension {
}

private fun checkTypeAlias(holder: RsAnnotationHolder, ta: RsTypeAlias) {
when (val owner = ta.owner) {
is RsAbstractableOwner.Trait -> {
ta.typeReference?.let { ASSOCIATED_TYPE_DEFAULTS.check(holder, it, "associated type defaults") }
val typeParameterList = ta.typeParameterList
if (typeParameterList != null && typeParameterList.genericParameterList.isNotEmpty()) {
GENERIC_ASSOCIATED_TYPES.check(holder, typeParameterList, "generic associated types")
}
ta.whereClause?.let { GENERIC_ASSOCIATED_TYPES.check(holder, it, "where clauses on associated types") }
}
is RsAbstractableOwner.Impl -> {
if (owner.isInherent) {
INHERENT_ASSOCIATED_TYPES.check(holder, ta, "inherent associated types")
}
val typeParameterList = ta.typeParameterList
if (typeParameterList != null && typeParameterList.genericParameterList.isNotEmpty()) {
GENERIC_ASSOCIATED_TYPES.check(holder, typeParameterList, "generic associated types")
}
ta.whereClause?.let { GENERIC_ASSOCIATED_TYPES.check(holder, it, "where clauses on associated types") }
}
is RsAbstractableOwner.Foreign -> {
EXTERN_TYPES.check(holder, ta, "extern types")
}
else -> {}
}

checkDuplicates(holder, ta)
}

Expand Down Expand Up @@ -1329,10 +1355,11 @@ class RsErrorAnnotator : AnnotatorBase(), HighlightRangeExtension {
}
}

private fun isInTraitImpl(o: RsVis): Boolean {
val impl = o.parent?.parent?.parent
return impl is RsImplItem && impl.traitRef != null
}
private fun isInTrait(o: RsVis): Boolean =
(o.parent as? RsAbstractable)?.owner is RsAbstractableOwner.Trait

private fun isInTraitImpl(o: RsVis): Boolean =
(o.parent as? RsAbstractable)?.owner?.isTraitImpl == true

private fun isInEnumVariantField(o: RsVis): Boolean {
val field = o.parent as? RsNamedFieldDecl
Expand Down
26 changes: 13 additions & 13 deletions src/main/kotlin/org/rust/ide/annotator/RsSyntaxErrorsAnnotator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -123,26 +123,26 @@ private fun checkTypeAlias(holder: AnnotationHolder, ta: RsTypeAlias) {
when (val owner = ta.owner) {
is RsAbstractableOwner.Free -> {
deny(ta.default, holder, "$title cannot have the `default` qualifier")
deny(ta.typeParamBounds, holder, "$title cannot have type parameter bounds")
require(ta.typeReference, holder, "Aliased type must be provided for type `${ta.identifier.text}`", ta)
deny(ta.typeParamBounds, holder, "Bounds on $title have no effect")
require(ta.typeReference, holder, "$title should have a body`", ta)
}
is RsAbstractableOwner.Trait -> {
deny(ta.default, holder, "$title cannot have the `default` qualifier")
deny(ta.vis, holder, "$title cannot have the `pub` qualifier")
deny(ta.typeParameterList, holder, "$title cannot have generic parameters")
deny(ta.whereClause, holder, "$title cannot have `where` clause")
}
is RsAbstractableOwner.Impl -> {
if (owner.impl.`for` == null) {
RsDiagnostic.AssociatedTypeInInherentImplError(ta).addToHolder(holder)
} else {
deny(ta.typeParameterList, holder, "$title cannot have generic parameters")
deny(ta.whereClause, holder, "$title cannot have `where` clause")
deny(ta.typeParamBounds, holder, "$title cannot have type parameter bounds")
require(ta.typeReference, holder, "Aliased type must be provided for type `${ta.identifier.text}`", ta)
if (owner.isInherent) {
deny(ta.default, holder, "$title cannot have the `default` qualifier")
}
deny(ta.typeParamBounds, holder, "Bounds on $title have no effect")
require(ta.typeReference, holder, "$title should have a body", ta)
}
RsAbstractableOwner.Foreign -> {
deny(ta.default, holder, "$title cannot have the `default` qualifier")
deny(ta.typeParameterList, holder, "$title cannot have generic parameters")
deny(ta.whereClause, holder, "$title cannot have `where` clause")
deny(ta.typeParamBounds, holder, "Bounds on $title have no effect")
deny(ta.typeReference, holder, "$title cannot have a body", ta)
}
RsAbstractableOwner.Foreign -> Unit
}
}

Expand Down
77 changes: 77 additions & 0 deletions src/test/kotlin/org/rust/ide/annotator/RsErrorAnnotatorTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4456,4 +4456,81 @@ class RsErrorAnnotatorTest : RsAnnotatorTestBase(RsErrorAnnotator::class) {
}
}
""")

@MockRustcVersion("1.23.0")
fun `test extern types E0658 1`() = checkErrors("""
extern { <error descr="extern types is experimental [E0658]">type ItemForeign;</error> }
""")

@MockRustcVersion("1.23.0-nightly")
fun `test extern types E0658 2`() = checkErrors("""
#![feature(extern_types)]
extern { type ItemForeign; }
""")

@MockRustcVersion("1.23.0")
fun `test generic associated types E0658 1`() = checkErrors("""
struct S;
type ItemFree<'a> where 'a : 'static = S;
impl S { <error>type Item<error descr="generic associated types is experimental [E0658]"><'a></error> <error descr="where clauses on associated types is experimental [E0658]">where 'a : 'static</error> = S;</error> }
trait T { type Item<error descr="generic associated types is experimental [E0658]"><'a></error> <error descr="where clauses on associated types is experimental [E0658]">where 'a : 'static</error>; }
impl T for S { type Item<error descr="generic associated types is experimental [E0658]"><'a></error> <error descr="where clauses on associated types is experimental [E0658]">where 'a : 'static</error> = S; }
""")

@MockRustcVersion("1.23.0-nightly")
fun `test generic associated types E0658 2`() = checkErrors("""
#![feature(generic_associated_types)]
struct S;
type ItemFree<'a> where 'a : 'static = S;
impl S { <error>type Item<'a> where 'a : 'static = S;</error> }
trait T { type Item<'a> where 'a : 'static; }
impl T for S { type Item<'a> where 'a : 'static = S; }
""")

fun `test generic associated types E0658 3`() = checkErrors("""
struct S;
type ItemFree<>;
impl S { type Item<>; }
trait T { type Item<>; }
impl T for S { type Item<>; }
""")

@MockRustcVersion("1.52.0")
fun `test inherent associated types E0658 1`() = checkErrors("""
impl S { <error descr="inherent associated types is experimental [E0658]">type Item;</error> }
""")

@MockRustcVersion("1.52.0-nightly")
fun `test inherent associated types E0658 2`() = checkErrors("""
#![feature(inherent_associated_types)]
impl S { type Item; }
""")

@MockRustcVersion("1.2.0")
fun `test associated type defaults E0658 1`() = checkErrors("""
struct S;
type ItemFree = S;
impl S { <error>type Item = S;</error> }
trait T { type Item = <error descr="associated type defaults is experimental [E0658]">S</error>; }
impl T for S { type Item = S; }
""")

@MockRustcVersion("1.2.0-nightly")
fun `test associated type defaults E0658 2`() = checkErrors("""
#![feature(associated_type_defaults)]
struct S;
type ItemFree = S;
impl S { <error>type Item = S;</error> }
trait T { type Item = S; }
impl T for S { type Item = S; }
""")

fun `test unnecessary visibility qualifier E0449`() = checkErrors("""
struct S;
pub type ItemFree = S;
impl S { pub type Item = S; }
trait T { <error descr="Unnecessary visibility qualifier [E0449]">pub</error> type Item; }
impl T for S { <error descr="Unnecessary visibility qualifier [E0449]">pub</error> type Item = S; }
extern { pub type ItemForeign; }
""")
}
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,8 @@ class RsSyntaxErrorsAnnotatorTest : RsAnnotatorTestBase(RsSyntaxErrorsAnnotator:
type SizedMaybe<T> where T: Sized = Option<T>;
<error descr="Type `DefBool` cannot have the `default` qualifier">default</error> type DefBool = bool;
<error descr="Aliased type must be provided for type `Unknown`">type Unknown;</error>
type Show<error descr="Type `Show` cannot have type parameter bounds">: Display</error> = u32;
<error descr="Type `Unknown` should have a body`">type Unknown;</error>
type Show<error descr="Bounds on Type `Show` have no effect">: Display</error> = u32;
""")

fun `test type alias in trait`() = checkErrors("""
Expand All @@ -119,14 +119,15 @@ class RsSyntaxErrorsAnnotatorTest : RsAnnotatorTestBase(RsSyntaxErrorsAnnotator:
type Show: Display;
<error descr="Type `DefSize` cannot have the `default` qualifier">default</error> type DefSize = isize;
<error descr="Type `PubType` cannot have the `pub` qualifier">pub</error> type PubType;
type GenType<error descr="Type `GenType` cannot have generic parameters"><T></error> = Option<T>;
type WhereType <error descr="Type `WhereType` cannot have `where` clause">where T: Sized</error> = f64;
pub type PubType;
type GenType<T> = Option<T>;
type WhereType where T: Sized = f64;
}
""")

fun `test type alias in trait impl`() = checkErrors("""
trait Vehicle {
type Unknown;
type Engine;
type Control;
type Lock;
Expand All @@ -136,15 +137,42 @@ class RsSyntaxErrorsAnnotatorTest : RsAnnotatorTestBase(RsSyntaxErrorsAnnotator:
}
struct NumericVehicle<T> { foo: T }
impl<T> Vehicle for NumericVehicle<T> {
<error descr="Type `Unknown` should have a body">type Unknown;</error>
type Engine = u32;
default type Control = isize;
type Lock<error descr="Type `Lock` cannot have generic parameters"><T></error> = Option<T>;
type Cage<error descr="Type `Cage` cannot have type parameter bounds">: Sized</error> = f64;
type Insurance <error descr="Type `Insurance` cannot have `where` clause">where T: Sized</error> = i8;
<error descr="Aliased type must be provided for type `Driver`">type Driver;</error>
type Lock<T> = Option<T>;
type Cage<error descr="Bounds on Type `Cage` have no effect">: Sized</error> = f64;
type Insurance where T: Sized = i8;
<error descr="Type `Driver` should have a body">type Driver;</error>
}
""")

fun `test type alias in inheret impl`() = checkErrors("""
struct S;
impl S {
<error descr="Type `Unknown` should have a body">type Unknown;</error>
type Engine = u32;
<error descr="Type `Control` cannot have the `default` qualifier">default</error> type Control = isize;
type Lock<T> = Option<T>;
type Cage<error descr="Bounds on Type `Cage` have no effect">: Sized</error> = f64;
type Insurance where T: Sized = i8;
<error descr="Type `Driver` should have a body">type Driver;</error>
}
""")

fun `test type alias in extern block`() = checkErrors("""
extern {
<error descr="Type `Int` cannot have a body">type Int = i32;</error>
<error descr="Type `UInt` cannot have a body">pub type UInt = u32;</error>
<error descr="Type `Maybe` cannot have a body">type Maybe<error descr="Type `Maybe` cannot have generic parameters"><T></error> = Option<T>;</error>
<error descr="Type `SizedMaybe` cannot have a body">type SizedMaybe<error descr="Type `SizedMaybe` cannot have generic parameters"><T></error> <error descr="Type `SizedMaybe` cannot have `where` clause">where T: Sized</error> = Option<T>;</error>
<error descr="Type `DefBool` cannot have a body"><error descr="Type `DefBool` cannot have the `default` qualifier">default</error> type DefBool = bool;</error>
type Unknown;
<error descr="Type `Show` cannot have a body">type Show<error descr="Bounds on Type `Show` have no effect">: Display</error> = u32;</error>
}
""")

fun `test const free`() = checkErrors("""
const FOO: u32 = 42;
pub const PUB_FOO: u32 = 41;
Expand Down Expand Up @@ -208,13 +236,6 @@ class RsSyntaxErrorsAnnotatorTest : RsAnnotatorTestBase(RsSyntaxErrorsAnnotator:
<error>default</error> fn two_errors(<error>u8</error>, a: i16) {}
""")

fun `test E0202 type alias in inherent impl`() = checkErrors("""
struct Foo;
impl Foo {
<error descr="Associated types are not allowed in inherent impls [E0202]">type Long = i64;</error>
}
""")

fun `test add parameter_name fix`() = checkFixByText("Add dummy parameter name", """
trait Display {
fn fmt(&self, <warning>F/*caret*/</warning>);
Expand Down

0 comments on commit b7b35c0

Please sign in to comment.