mirror of
https://github.com/luau-lang/luau.git
synced 2024-12-13 21:40:43 +00:00
99 lines
5.3 KiB
Agda
99 lines
5.3 KiB
Agda
|
{-# OPTIONS --rewriting #-}
|
|||
|
|
|||
|
module Luau.ResolveOverloads where
|
|||
|
|
|||
|
open import FFI.Data.Either using (Left; Right)
|
|||
|
open import Luau.Subtyping using (_<:_; _≮:_; Language; witness; scalar; unknown; never; function-ok)
|
|||
|
open import Luau.Type using (Type ; _⇒_; _∩_; _∪_; unknown; never)
|
|||
|
open import Luau.TypeSaturation using (saturate)
|
|||
|
open import Luau.TypeNormalization using (normalize)
|
|||
|
open import Properties.Contradiction using (CONTRADICTION)
|
|||
|
open import Properties.DecSubtyping using (dec-subtyping; dec-subtypingⁿ; <:-impl-<:ᵒ)
|
|||
|
open import Properties.Functions using (_∘_)
|
|||
|
open import Properties.Subtyping using (<:-refl; <:-trans; <:-trans-≮:; ≮:-trans-<:; <:-∩-left; <:-∩-right; <:-∩-glb; <:-impl-¬≮:; <:-unknown; <:-function; function-≮:-never; <:-never; unknown-≮:-function; scalar-≮:-function; ≮:-∪-right; scalar-≮:-never; <:-∪-left; <:-∪-right)
|
|||
|
open import Properties.TypeNormalization using (Normal; FunType; normal; _⇒_; _∩_; _∪_; never; unknown; <:-normalize; normalize-<:; fun-≮:-never; unknown-≮:-fun; scalar-≮:-fun)
|
|||
|
open import Properties.TypeSaturation using (Overloads; Saturated; _⊆ᵒ_; _<:ᵒ_; normal-saturate; saturated; <:-saturate; saturate-<:; defn; here; left; right)
|
|||
|
|
|||
|
-- The domain of a normalized type
|
|||
|
srcⁿ : Type → Type
|
|||
|
srcⁿ (S ⇒ T) = S
|
|||
|
srcⁿ (S ∩ T) = srcⁿ S ∪ srcⁿ T
|
|||
|
srcⁿ never = unknown
|
|||
|
srcⁿ T = never
|
|||
|
|
|||
|
-- To get the domain of a type, we normalize it first We need to do
|
|||
|
-- this, since if we try to use it on non-normalized types, we get
|
|||
|
--
|
|||
|
-- src(number ∩ string) = src(number) ∪ src(string) = never ∪ never
|
|||
|
-- src(never) = unknown
|
|||
|
--
|
|||
|
-- so src doesn't respect type equivalence.
|
|||
|
src : Type → Type
|
|||
|
src (S ⇒ T) = S
|
|||
|
src T = srcⁿ(normalize T)
|
|||
|
|
|||
|
-- Calculate the result of applying a function type `F` to an argument type `V`.
|
|||
|
-- We do this by finding an overload of `F` that has the most precise type,
|
|||
|
-- that is an overload `(Sʳ ⇒ Tʳ)` where `V <: Sʳ` and moreover
|
|||
|
-- for any other such overload `(S ⇒ T)` we have that `Tʳ <: T`.
|
|||
|
|
|||
|
-- For example if `F` is `(number -> number) & (nil -> nil) & (number? -> number?)`
|
|||
|
-- then to resolve `F` with argument type `number`, we pick the `number -> number`
|
|||
|
-- overload, but if the argument is `number?`, we pick `number? -> number?`./
|
|||
|
|
|||
|
-- Not all types have such a most precise overload, but saturated ones do.
|
|||
|
|
|||
|
data ResolvedTo F G V : Set where
|
|||
|
|
|||
|
yes : ∀ Sʳ Tʳ →
|
|||
|
|
|||
|
Overloads F (Sʳ ⇒ Tʳ) →
|
|||
|
(V <: Sʳ) →
|
|||
|
(∀ {S T} → Overloads G (S ⇒ T) → (V <: S) → (Tʳ <: T)) →
|
|||
|
--------------------------------------------
|
|||
|
ResolvedTo F G V
|
|||
|
|
|||
|
no :
|
|||
|
|
|||
|
(∀ {S T} → Overloads G (S ⇒ T) → (V ≮: S)) →
|
|||
|
--------------------------------------------
|
|||
|
ResolvedTo F G V
|
|||
|
|
|||
|
Resolved : Type → Type → Set
|
|||
|
Resolved F V = ResolvedTo F F V
|
|||
|
|
|||
|
target : ∀ {F V} → Resolved F V → Type
|
|||
|
target (yes _ T _ _ _) = T
|
|||
|
target (no _) = unknown
|
|||
|
|
|||
|
-- We can resolve any saturated function type
|
|||
|
resolveˢ : ∀ {F G V} → FunType G → Saturated F → Normal V → (G ⊆ᵒ F) → ResolvedTo F G V
|
|||
|
resolveˢ (Sⁿ ⇒ Tⁿ) (defn sat-∩ sat-∪) Vⁿ G⊆F with dec-subtypingⁿ Vⁿ Sⁿ
|
|||
|
resolveˢ (Sⁿ ⇒ Tⁿ) (defn sat-∩ sat-∪) Vⁿ G⊆F | Left V≮:S = no (λ { here → V≮:S })
|
|||
|
resolveˢ (Sⁿ ⇒ Tⁿ) (defn sat-∩ sat-∪) Vⁿ G⊆F | Right V<:S = yes _ _ (G⊆F here) V<:S (λ { here _ → <:-refl })
|
|||
|
resolveˢ (Gᶠ ∩ Hᶠ) (defn sat-∩ sat-∪) Vⁿ G⊆F with resolveˢ Gᶠ (defn sat-∩ sat-∪) Vⁿ (G⊆F ∘ left) | resolveˢ Hᶠ (defn sat-∩ sat-∪) Vⁿ (G⊆F ∘ right)
|
|||
|
resolveˢ (Gᶠ ∩ Hᶠ) (defn sat-∩ sat-∪) Vⁿ G⊆F | yes S₁ T₁ o₁ V<:S₁ tgt₁ | yes S₂ T₂ o₂ V<:S₂ tgt₂ with sat-∩ o₁ o₂
|
|||
|
resolveˢ (Gᶠ ∩ Hᶠ) (defn sat-∩ sat-∪) Vⁿ G⊆F | yes S₁ T₁ o₁ V<:S₁ tgt₁ | yes S₂ T₂ o₂ V<:S₂ tgt₂ | defn o p₁ p₂ =
|
|||
|
yes _ _ o (<:-trans (<:-∩-glb V<:S₁ V<:S₂) p₁) (λ { (left o) p → <:-trans p₂ (<:-trans <:-∩-left (tgt₁ o p)) ; (right o) p → <:-trans p₂ (<:-trans <:-∩-right (tgt₂ o p)) })
|
|||
|
resolveˢ (Gᶠ ∩ Hᶠ) (defn sat-∩ sat-∪) Vⁿ G⊆F | yes S₁ T₁ o₁ V<:S₁ tgt₁ | no src₂ =
|
|||
|
yes _ _ o₁ V<:S₁ (λ { (left o) p → tgt₁ o p ; (right o) p → CONTRADICTION (<:-impl-¬≮: p (src₂ o)) })
|
|||
|
resolveˢ (Gᶠ ∩ Hᶠ) (defn sat-∩ sat-∪) Vⁿ G⊆F | no src₁ | yes S₂ T₂ o₂ V<:S₂ tgt₂ =
|
|||
|
yes _ _ o₂ V<:S₂ (λ { (left o) p → CONTRADICTION (<:-impl-¬≮: p (src₁ o)) ; (right o) p → tgt₂ o p })
|
|||
|
resolveˢ (Gᶠ ∩ Hᶠ) (defn sat-∩ sat-∪) Vⁿ G⊆F | no src₁ | no src₂ =
|
|||
|
no (λ { (left o) → src₁ o ; (right o) → src₂ o })
|
|||
|
|
|||
|
-- Which means we can resolve any normalized type, by saturating it first
|
|||
|
resolveᶠ : ∀ {F V} → FunType F → Normal V → Type
|
|||
|
resolveᶠ Fᶠ Vⁿ = target (resolveˢ (normal-saturate Fᶠ) (saturated Fᶠ) Vⁿ (λ o → o))
|
|||
|
|
|||
|
resolveⁿ : ∀ {F V} → Normal F → Normal V → Type
|
|||
|
resolveⁿ (Sⁿ ⇒ Tⁿ) Vⁿ = resolveᶠ (Sⁿ ⇒ Tⁿ) Vⁿ
|
|||
|
resolveⁿ (Fᶠ ∩ Gᶠ) Vⁿ = resolveᶠ (Fᶠ ∩ Gᶠ) Vⁿ
|
|||
|
resolveⁿ (Sⁿ ∪ Tˢ) Vⁿ = unknown
|
|||
|
resolveⁿ unknown Vⁿ = unknown
|
|||
|
resolveⁿ never Vⁿ = never
|
|||
|
|
|||
|
-- Which means we can resolve any type, by normalizing it first
|
|||
|
resolve : Type → Type → Type
|
|||
|
resolve F V = resolveⁿ (normal F) (normal V)
|