luau/prototyping/Luau/ResolveOverloads.agda
2022-06-14 20:03:43 -07:00

98 lines
5.3 KiB
Agda
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{-# 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 :
Overloads F ( )
(V <: )
( {S T} Overloads G (S T) (V <: S) ( <: 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ⁿ ) 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)