mirror of
https://github.com/luau-lang/luau.git
synced 2024-12-13 05:20:38 +00:00
98 lines
5.3 KiB
Agda
98 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)
|