Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

일관성(Coherence)

참고: 이 문서는 @lcnr의 노트를 바탕으로 작성되었습니다.

일관성 검사는 트레이트 impl과 고유 impl이 다른 impl과 겹치는지를 모두 검출하는 과정입니다. (참고로, 고유 impl은 impl MyStruct {}처럼 구체 타입에 대한 impl입니다.)

겹치는 트레이트 impl은 항상 오류를 발생시키지만, 겹치는 고유 impl은 같은 이름의 메서드를 가지는 경우에만 오류가 됩니다.

겹침 검사는 두 부분으로 나뉩니다. 첫째는 겹침 검사로, 컴파일러가 현재 알고 있는 트레이트 구현과 고유 구현 사이의 겹침을 찾아냅니다.

그러나 일관성 검사는 현재 알려져 있지 않더라도 다른 impl이 존재할 수 있는 경우에도 오류를 발생시킵니다. 이는 업스트림 크레이트에 하위 호환되는 방식으로 추가될 수 있는 impl과 다운스트림 크레이트의 impl에 영향을 미칩니다. 이것을 고아 검사(Orphan check)라고 합니다.

겹침 검사

겹침 검사는 고유 impl과 트레이트 impl 모두에 대해 수행됩니다. 두 검사는 같은 겹침 검사 코드를 사용하지만, 실제로는 별개의 두 분석으로 수행됩니다. 겹침 검사는 항상 구현을 쌍으로 묶어 서로 비교합니다.

고유 impl 블록에 대한 겹침 검사는 fn check_item(coherence/inherent_impls_overlap.rs 내)을 통해 수행되며, 여기서 이 검사가 (적어도 작은 n에 대해서는) 실제로 impl 사이에 n^2번의 비교를 수행한다는 것을 매우 분명하게 확인할 수 있습니다.

트레이트의 경우, 부모와 겹치는 특수화 impl을 처리하기 위해 현재 이 검사는 특수화 그래프를 구축하는 과정의 일부로 수행되지만, 이는 향후 바뀔 수 있습니다.

두 경우 모두 모든 impl 쌍에 대해 겹침 여부를 검사합니다.

겹침은 때때로 부분적으로 허용됩니다.

  1. 마커 트레이트의 경우
  2. 특수화를 사용하는 경우

일반적으로는 허용되지 않습니다.

겹침 검사에는 여러 모드가 있습니다(OverlapMode 참조). 중요한 것은 명시적 부정 impl 검사와 암시적 부정 impl 검사가 있다는 점입니다. 두 검사 모두 겹침이 절대로 불가능하다는 것을 증명하려고 시도합니다.

명시적 부정 impl 검사

이 검사는 impl_intersection_has_negative_obligation에서 수행됩니다.

이 검사는 부정 트레이트 구현을 찾으려고 시도합니다. 예를 들면 다음과 같습니다.

#![allow(unused)]
fn main() {
struct MyCustomErrorType;

// both in your own crate
impl From<&str> for MyCustomErrorType {}
impl<E> From<E> for MyCustomErrorType where E: Error {}
}

이 예제에서는 MyCustomErrorType: From<&str>와 MyCustomErrorType: From<?E>를 얻게 되며, 이로부터 ?E = &str이 도출됩니다.

따라서 이 두 구현은 겹치게 됩니다. 그러나 libstd는 &str: !Error를 제공하므로 &str: Error의 긍정 구현이 절대 존재하지 않을 것임을 보장하며, 따라서 겹침이 없습니다.

이러한 종류의 부정 impl 검사를 위해서는 명시적인 부정 구현이 제공되어야 한다는 점에 유의하십시오. 이 기능은 현재 안정화되지 않았습니다.

암묵적 부정 impl 검사

이 검사는 impl_intersection_has_impossible_obligation에서 수행되며, 부정 트레이트 구현에 의존하지 않고 안정화되어 있습니다.

다음과 같은 코드가 있다고 가정해 봅시다.

#![allow(unused)]
fn main() {
impl From<MyLocalType> for Box<dyn Error> {}  // in your own crate
impl<E> From<E> for Box<dyn Error> where E: Error {} // in std
}

이 경우 Box<dyn Error>: From<MyLocalType>와 Box<dyn Error>: From<?E>가 나오고, 그 결과 ?E = MyLocalType이 됩니다.

여러분의 크레이트에는 MyLocalType: Error가 없으며, 하위 크레이트는 MyLocalType(원격 타입)에 대해 Error(원격 트레이트)를 구현할 수 없습니다. 따라서 이 두 impl은 겹치지 않습니다. 중요한 점은 impl !Error for MyLocalType가 없더라도 이 방식이 동작한다는 것입니다.