Skip to content

Commit

Permalink
Introduce EDITION_2021
Browse files Browse the repository at this point in the history
Initial preparation for 2021 edition
  • Loading branch information
Undin committed Apr 14, 2021
1 parent 174726c commit 3c94085
Show file tree
Hide file tree
Showing 16 changed files with 39 additions and 34 deletions.
Expand Up @@ -201,7 +201,9 @@ interface CargoWorkspace {
}

enum class Edition(val presentation: String) {
EDITION_2015("2015"), EDITION_2018("2018")
EDITION_2015("2015"),
EDITION_2018("2018"),
EDITION_2021("2021")
}

companion object {
Expand Down
Expand Up @@ -515,6 +515,7 @@ object CargoMetadata {
private fun String?.cleanEdition(): Edition = when (this) {
Edition.EDITION_2015.presentation -> Edition.EDITION_2015
Edition.EDITION_2018.presentation -> Edition.EDITION_2018
Edition.EDITION_2021.presentation -> Edition.EDITION_2021
else -> Edition.EDITION_2015
}

Expand Down
Expand Up @@ -12,7 +12,6 @@ import com.intellij.openapi.editor.colors.EditorColorsManager
import com.intellij.openapi.editor.markup.TextAttributes
import com.intellij.openapiext.isUnitTestMode
import com.intellij.psi.PsiElement
import org.rust.cargo.project.workspace.CargoWorkspace
import org.rust.ide.colors.RsColor
import org.rust.ide.utils.isEnabledByCfg
import org.rust.lang.core.psi.*
Expand All @@ -21,26 +20,26 @@ import org.rust.lang.core.psi.ext.*

class RsEdition2018KeywordsAnnotator : AnnotatorBase() {
override fun annotateInternal(element: PsiElement, holder: AnnotationHolder) {
val edition = element.edition ?: return
if (element.edition == null) return

if (!isEdition2018Keyword(element)) return

val isEdition2018 = edition == CargoWorkspace.Edition.EDITION_2018
val isAtLeastEdition2018 = element.isAtLeastEdition2018
val isIdentifier = element.elementType == IDENTIFIER
val isEnabledByCfg = element.isEnabledByCfg
when {
isEdition2018 && isIdentifier && isNameIdentifier(element) ->
isAtLeastEdition2018 && isIdentifier && isNameIdentifier(element) ->
holder.newAnnotation(HighlightSeverity.ERROR, "`${element.text}` is reserved keyword in Edition 2018").create()

isEdition2018 && !isIdentifier && isEnabledByCfg -> {
isAtLeastEdition2018 && !isIdentifier && isEnabledByCfg -> {
if (!holder.isBatchMode) {
val severity = if (isUnitTestMode) RsColor.KEYWORD.testSeverity else HighlightSeverity.INFORMATION
holder.newSilentAnnotation(severity)
.textAttributes(RsColor.KEYWORD.textAttributesKey).create()
}
}

isEdition2018 && !isIdentifier && !isEnabledByCfg -> {
isAtLeastEdition2018 && !isIdentifier && !isEnabledByCfg -> {
if (!holder.isBatchMode) {
val colorScheme = EditorColorsManager.getInstance().globalScheme
val keywordTextAttributes = colorScheme.getAttributes(RsColor.KEYWORD.textAttributesKey)
Expand All @@ -52,7 +51,7 @@ class RsEdition2018KeywordsAnnotator : AnnotatorBase() {
}
}

!isEdition2018 && !isIdentifier ->
!isAtLeastEdition2018 && !isIdentifier ->
holder.newAnnotation(HighlightSeverity.ERROR, "This feature is only available in Edition 2018").create()
}
}
Expand Down
Expand Up @@ -116,7 +116,7 @@ class RsHighlightingAnnotator : AnnotatorBase() {
isPrimitiveType -> RsColor.PRIMITIVE_TYPE
parent is RsMacroCall -> if (shouldHighlightMacroCall(parent, holder)) RsColor.MACRO else null
element is RsMethodCall -> RsColor.METHOD_CALL
element is RsFieldLookup && element.identifier?.text == "await" && element.isEdition2018 -> RsColor.KEYWORD
element is RsFieldLookup && element.identifier?.text == "await" && element.isAtLeastEdition2018 -> RsColor.KEYWORD
element is RsPath && element.isCall() -> {
val ref = reference?.resolve() ?: return null
if (ref is RsFunction) {
Expand Down
Expand Up @@ -91,7 +91,7 @@ class AttachFileToModuleFix(
modules.addIfNotNull(findModule(file, project, directory.findFileByRelativePath(RsConstants.MOD_RS_FILE)))

// module file in parent directory
if (pkg.edition == CargoWorkspace.Edition.EDITION_2018) {
if (pkg.edition >= CargoWorkspace.Edition.EDITION_2018) {
modules.addIfNotNull(findModule(file, project, directory.parent?.findFileByRelativePath("${directory.name}.rs")))
}

Expand Down
Expand Up @@ -12,7 +12,7 @@ import com.intellij.psi.PsiElement
import org.rust.ide.inspections.RsProblemsHolder
import org.rust.lang.core.psi.*
import org.rust.lang.core.psi.ext.dyn
import org.rust.lang.core.psi.ext.isEdition2018
import org.rust.lang.core.psi.ext.isAtLeastEdition2018
import org.rust.lang.core.psi.ext.skipParens
import org.rust.lang.core.resolve.ref.deepResolve

Expand All @@ -22,7 +22,7 @@ class RsBareTraitObjectsInspection : RsLintInspection() {
override fun buildVisitor(holder: RsProblemsHolder, isOnTheFly: Boolean): RsVisitor =
object : RsVisitor() {
override fun visitTypeReference(typeReference: RsTypeReference) {
if (!typeReference.isEdition2018) return
if (!typeReference.isAtLeastEdition2018) return

val traitType = typeReference.skipParens() as? RsTraitType
val baseTypePath = (typeReference.skipParens() as? RsBaseType)?.path
Expand Down
Expand Up @@ -38,7 +38,7 @@ class CreateFunctionIntention : RsElementBaseIntentionAction<CreateFunctionInten

sealed class Context(val name: String, val callElement: PsiElement) {
abstract val visibility: String
open val isAsync: Boolean = callElement.isEdition2018
open val isAsync: Boolean = callElement.isAtLeastEdition2018
abstract val arguments: RsValueArgumentList
abstract val returnType: Ty?
open val implItem: RsImplItem? = null
Expand Down
Expand Up @@ -20,7 +20,7 @@ import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectori
import com.intellij.refactoring.util.CommonRefactoringUtil
import org.rust.lang.RsLanguage
import org.rust.lang.core.psi.RsFile
import org.rust.lang.core.psi.ext.isEdition2018
import org.rust.lang.core.psi.ext.isAtLeastEdition2018
import org.rust.stdext.mapToSet

class RsMoveFilesOrDirectoriesHandler : MoveFilesOrDirectoriesHandler() {
Expand Down Expand Up @@ -118,5 +118,5 @@ private fun RsFile.canBeMoved(): Boolean =
&& crateRoot != null
&& crateRelativePath != null
&& !isCrateRoot
&& isEdition2018 // TODO: support 2015 edition
&& isAtLeastEdition2018 // TODO: support 2015 edition
&& pathAttribute == null // TODO: support path attribute on mod declaration
Expand Up @@ -191,7 +191,7 @@ object ImportCandidatesCollector {
ourSuperMods to importInfo
} else {
val targetMod = superMods.first()
val relativePath = if (targetMod.isEdition2018) {
val relativePath = if (targetMod.isAtLeastEdition2018) {
"crate::$crateRelativePath"
} else {
crateRelativePath
Expand Down
4 changes: 2 additions & 2 deletions src/main/kotlin/org/rust/ide/utils/import/importUtils.kt
Expand Up @@ -25,7 +25,7 @@ fun ImportCandidate.import(context: RsElement) {
// we uses this info to create correct relative use item path if needed
var relativeDepth: Int? = null

val isEdition2018 = context.isEdition2018
val isAtLeastEdition2018 = context.isAtLeastEdition2018
val info = info
// if crate of importing element differs from current crate
// we need to add new extern crate item
Expand All @@ -42,7 +42,7 @@ fun ImportCandidate.import(context: RsElement) {
// we don't add corresponding extern crate item manually for the same reason
attributes == RsFile.Attributes.NO_STD && crate.isCore -> Testmarks.autoInjectedCoreCrate.hit()
else -> {
if (info.needInsertExternCrateItem && !isEdition2018) {
if (info.needInsertExternCrateItem && !isAtLeastEdition2018) {
crateRoot?.insertExternCrateItem(psiFactory, info.externCrateName)
} else {
if (info.depth != null) {
Expand Down
Expand Up @@ -17,7 +17,7 @@ import com.intellij.util.ProcessingContext
import org.rust.lang.core.psi.RsElementTypes
import org.rust.lang.core.psi.RsFieldLookup
import org.rust.lang.core.psi.ext.findAssociatedType
import org.rust.lang.core.psi.ext.isEdition2018
import org.rust.lang.core.psi.ext.isAtLeastEdition2018
import org.rust.lang.core.psi.ext.receiver
import org.rust.lang.core.psi.ext.withSubst
import org.rust.lang.core.psiElement
Expand All @@ -36,7 +36,7 @@ object RsAwaitCompletionProvider : RsCompletionProvider() {
val parent = psiElement<RsFieldLookup>()
.with(object : PatternCondition<RsFieldLookup>("RsPostfixAwait") {
override fun accepts(t: RsFieldLookup, context: ProcessingContext?): Boolean {
if (context == null || !t.isEdition2018) return false
if (context == null || !t.isAtLeastEdition2018) return false
val receiver = t.receiver.safeGetOriginalOrSelf()
val lookup = ImplLookup.relativeTo(receiver)
val awaitTy = receiver.type.lookupFutureOutputTy(lookup)
Expand Down
7 changes: 5 additions & 2 deletions src/main/kotlin/org/rust/lang/core/psi/ext/RsElement.kt
Expand Up @@ -65,8 +65,11 @@ val RsElement.containingCargoPackage: CargoWorkspace.Package? get() = containing
val PsiElement.edition: CargoWorkspace.Edition?
get() = contextOrSelf<RsElement>()?.containingCrate?.edition

val PsiElement.isEdition2018: Boolean
get() = edition == CargoWorkspace.Edition.EDITION_2018
val PsiElement.isAtLeastEdition2018: Boolean
get() {
val edition = edition ?: return false
return edition >= CargoWorkspace.Edition.EDITION_2018
}

/**
* It is possible to match value with constant-like element, e.g.
Expand Down
10 changes: 5 additions & 5 deletions src/main/kotlin/org/rust/lang/core/resolve/ItemResolution.kt
Expand Up @@ -110,12 +110,12 @@ fun processItemDeclarations(
}
}

val isEdition2018 = scope.isEdition2018
val isAtLeastEdition2018 = scope.isAtLeastEdition2018
for ((isPublic, path, name, isAtom) in cachedItems.namedImports) {
if (!(isPublic || withPrivateImports)) continue

if (isEdition2018 && isAtom) {
// Use items like `use foo;` or `use foo::{self}` are meaningful on 2018 edition
if (isAtLeastEdition2018 && isAtom) {
// Use items like `use foo;` or `use foo::{self}` are meaningful since 2018 edition
// only if `foo` is a crate, and it is `pub use` item. Otherwise,
// we should ignore it or it breaks resolve of such `foo` in other places.
ItemResolutionTestmarks.extraAtomUse.hit()
Expand All @@ -131,7 +131,7 @@ fun processItemDeclarations(
}
}

if (withPrivateImports && Namespace.Types in ns && scope is RsFile && !isEdition2018 && scope.isCrateRoot) {
if (withPrivateImports && Namespace.Types in ns && scope is RsFile && !isAtLeastEdition2018 && scope.isCrateRoot) {
// Rust injects implicit `extern crate std` in every crate root module unless it is
// a `#![no_std]` crate, in which case `extern crate core` is injected. However, if
// there is a (unstable?) `#![no_core]` attribute, nothing is injected.
Expand All @@ -154,7 +154,7 @@ fun processItemDeclarations(
}

if (ipm.withExternCrates && Namespace.Types in ns && scope is RsMod) {
if (isEdition2018 && !scope.isCrateRoot) {
if (isAtLeastEdition2018 && !scope.isCrateRoot) {
val crateRoot = scope.crateRoot
if (crateRoot != null) {
val result = processWithShadowingAndUpdateScope(directlyDeclaredNames, originalProcessor) { shadowingProcessor ->
Expand Down
10 changes: 5 additions & 5 deletions src/main/kotlin/org/rust/lang/core/resolve/NameResolution.kt
Expand Up @@ -554,7 +554,7 @@ private fun processUnqualifiedPathResolveVariants(
}
}

val isEdition2018 = (crateRoot ?: containingMod).isEdition2018
val isAtLeastEdition2018 = (crateRoot ?: containingMod).isAtLeastEdition2018

// In 2015 edition a path is crate-relative (global) if it's inside use item,
// inside "visibility restriction" or if it starts with `::`
Expand All @@ -564,13 +564,13 @@ private fun processUnqualifiedPathResolveVariants(
// pub(in foo::bar) fn baz() {}
// //^ crate-relative path too
// ```
// In 2018 edition a path is crate-relative if it starts with `crate::` (handled above)
// or if it's inside "visibility restriction". `::`-qualified path on 2018 edition means that
// Starting 2018 edition a path is crate-relative if it starts with `crate::` (handled above)
// or if it's inside "visibility restriction". `::`-qualified path since 2018 edition means that
// such path is a name of some dependency crate (that should be resolved without `extern crate`)
val isCrateRelative = !isEdition2018 && (hasColonColon || path.rootPath().parent is RsUseSpeck)
val isCrateRelative = !isAtLeastEdition2018 && (hasColonColon || path.rootPath().parent is RsUseSpeck)
|| path.rootPath().parent is RsVisRestriction
// see https://doc.rust-lang.org/edition-guide/rust-2018/module-system/path-clarity.html#the-crate-keyword-refers-to-the-current-crate
val isExternCrate = isEdition2018 && hasColonColon
val isExternCrate = isAtLeastEdition2018 && hasColonColon
return when {
isCrateRelative -> if (crateRoot != null) {
processItemOrEnumVariantDeclarations(crateRoot, ns, processor, withPrivateImports = { true })
Expand Down
Expand Up @@ -123,7 +123,7 @@ class RsPathReferenceImpl(
}

private fun bindToMod(target: RsMod): PsiElement? {
if (!element.isEdition2018) return null
if (!element.isAtLeastEdition2018) return null
var targetPath = target.qualifiedNameRelativeTo(element.containingMod) ?: return null

// consider old target (`element.reference.resolve()`) was `bar1::bar2::bar3::bar4::foo`
Expand Down
Expand Up @@ -792,7 +792,7 @@ class RsTypeInferenceWalker(
}

private fun inferFieldExprType(receiver: Ty, fieldLookup: RsFieldLookup): Ty {
if (fieldLookup.identifier?.text == "await" && fieldLookup.isEdition2018) {
if (fieldLookup.identifier?.text == "await" && fieldLookup.isAtLeastEdition2018) {
return receiver.lookupFutureOutputTy(lookup)
}

Expand Down

0 comments on commit 3c94085

Please sign in to comment.